您的位置:首页 > 移动开发 > Android开发

向android 的状态栏中加入快捷按钮(home,back,menu等等)的方法(续)

2010-11-24 22:13 489 查看
上一篇文章中谈到的加入快捷按钮的方法,实际上还是太过麻烦。那篇博客是在我刚接触android源代码没几天时,参考网上的介绍方法,自己看了下源代码尝试着写了一个。 不过那个方法,是我直接用贴图的方法实现了按钮特效,这实在是太浪费了,最近一直仍有朋友问我那篇文章中的问题,我想还是重写一下,用一个更简单点的方法,直接使用android的ImageButton控件,通过其OnTouchListener方法操作即可,Button的高亮与否完全由系统处理,这样也不会出现button高亮不消失的bug。以下方法在android 2.1 上编译调试通过

1。 准备资源,修改XML文件

和上篇文章一样,准备几张图,这里我们准备添加home back和menu图标,就需要准备6张图,三张普通状态,三张按下的高亮状态图标:

stat_home.png
stat_home_pressed.png
stat_back.png
stat_back_pressed.png
stat_menu.png
stat_menu_pressed.png

同时,在 Frameworks/base/core/res/res/drawable下创建三个imageButton的xml文件:

xml_stat_home.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_focused="true"
android:state_pressed="false"
android:drawable="@drawable/stat_home" />
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/stat_home_pressed" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="@drawable/stat_home_pressed" />
<item
android:drawable="@drawable/stat_home" />
</selector>


xml_stat_back.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_focused="true"
android:state_pressed="false"
android:drawable="@drawable/stat_back" />
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/stat_back_pressed" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="@drawable/stat_back_pressed" />
<item
android:drawable="@drawable/stat_back" />
</selector>

xml_stat_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_focused="true"
android:state_pressed="false"
android:drawable="@drawable/stat_menu" />
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="@drawable/stat_menu_pressed" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="@drawable/stat_menu_pressed" />
<item
android:drawable="@drawable/stat_menu" />
</selector>


修改status_bar.xml,如下:

<?xml version="1.0" encoding="utf-8"?>
<!--
/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0 **
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<!--    android:background="@drawable/status_bar_closed_default_background" -->
<com.android.server.status.StatusBarView xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/statusbar_background"
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
>

<LinearLayout android:id="@+id/icons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">

<ImageButton android:id="@+id/go_home"
android:layout_width="36px"
android:layout_height="36px"
android:layout_marginRight="15px"
android:layout_marginLeft="10px"
android:layout_marginTop="5px"
android:clickable="true"
android:background="@drawable/xml_stat_home"
/>

<com.android.server.status.IconMerger android:id="@+id/notificationIcons"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:paddingLeft="6dip"
android:gravity="center_vertical"
android:orientation="horizontal"/>

<LinearLayout android:id="@+id/statusIcons"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:paddingRight="6dip"
android:gravity="center_vertical"
android:orientation="horizontal"/>

<ImageButton android:id="@+id/pop_menu"
android:layout_width="36px"
android:layout_height="36px"
android:layout_marginRight="15px"
android:layout_marginLeft="10px"
android:layout_marginTop="5px"
android:clickable="true"
android:background="@drawable/xml_stat_menu"
/>
<ImageButton android:id="@+id/go_back"
android:layout_width="36px"
android:layout_height="36px"
android:layout_marginRight="15px"
android:layout_marginLeft="10px"
android:layout_marginTop="5px"
android:clickable="true"
android:background="@drawable/xml_stat_back"
/>
</LinearLayout>

<LinearLayout android:id="@+id/ticker"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="6dip"
android:animationCache="false"
android:orientation="horizontal" >
<ImageSwitcher android:id="@+id/tickerIcon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="8dip"
>
<com.android.server.status.AnimatedImageView
android:layout_width="36dip"
android:layout_height="36dip"
/>
<com.android.server.status.AnimatedImageView
android:layout_width="36dip"
android:layout_height="36dip"
/>
</ImageSwitcher>
<com.android.server.status.TickerView android:id="@+id/tickerText"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingRight="10dip">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="#ff000000" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="#ff000000" />
</com.android.server.status.TickerView>
</LinearLayout>

<com.android.server.status.DateView android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:singleLine="true"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center_vertical|left"
android:paddingLeft="6px"
android:paddingRight="6px"
android:textColor="?android:attr/textColorPrimaryInverse"
android:background="@drawable/statusbar_background"
/>
</com.android.server.status.StatusBarView>


如上篇,修改statusbar的高度,编译一下,即可看到效果。

2。 添加按钮的动作效果

在statusBarView.java中,活的button的handler

类中新增加三个成员:

ImageButton mHomeBtn;
ImageButton mBackBtn;
ImageButton mMenuBtn;


增加三个常量:

public static final int RESV_KEY_HOME = KeyEvent.KEYCODE_HOME;
public static final int RESV_KEY_BACK = KeyEvent.KEYCODE_BACK;
public static final int RESV_KEY_MENU = KeyEvent.KEYCODE_MENU;;

在onFinishInflate中,获取几个button 的handler,并设置touch事件,添加如下代码:

mHomeBtn = (ImageButton)findViewById(R.id.go_home);
mBackBtn = (ImageButton)findViewById(R.id.go_back);
mMenuBtn = (ImageButton)findViewById(R.id.pop_menu);

mHomeBtn.setOnTouchListener(homeOnTouch);
mBackBtn.setOnTouchListener(backOnTouch);
mMenuBtn.setOnTouchListener(menuOnTouch);


各button的touch事件添加如下:

private void sendKeyIntent(int keycode){
Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("keycode",   keycode);
mService.sendIntent(intent);
}

private OnTouchListener homeOnTouch = new OnTouchListener(){
//@Override
public boolean onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
{
sendKeyIntent(RESV_KEY_HOME);
}
break;
}
return false;
}
};

private OnTouchListener backOnTouch = new OnTouchListener(){
//@Override
public boolean onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
{
sendKeyIntent(RESV_KEY_BACK);
}
break;
}
return false;
}
};

private OnTouchListener menuOnTouch = new OnTouchListener(){
//@Override
public boolean onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
{
sendKeyIntent(RESV_KEY_MENU);
}
break;
}
return false;
}
};


也就是简单的广播一个intent消息给statusBarPolicy处理。

为防止点击statusBar上的按钮, 触发标题栏的expend事件, 修改一下函数onInterceptTouchEvent,点击到不属于button区域时才允许解析Motion的event:

public boolean onInterceptTouchEvent(MotionEvent event) {
if(  (event.getX() > mHomeBtn.getRight())
&&  (event.getX() < mMenuBtn.getLeft())){
return mService.interceptTouchEvent(event)
? true : super.onInterceptTouchEvent(event);
}
return false;
//return mService.interceptTouchEvent(event)
//	? true : super.onInterceptTouchEvent(event);
}
}


修改StatusBarService.java,发送Intent消息需要content,这个目前只能在StatusBarService中添加一个方法:

void sendIntent(Intent intent)
{
mContext.sendBroadcast(intent);
}


要发送intent,需要自己添加Intent:

在framework/base/core/java/android/content/intent.java中增加

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ICONKEY_CHANGED = "android.intent.action.ICONKEY_CHANGED";


接收并处理intent, 如前篇:

接收并处理intent

这个就要修改StatusBarPolicy.java了

首先,在构造函数中加入Intent的filter,注册号这个intent的receiver。

filter.addAction(Intent.ACTION_ICONKEY_CHANGED);


然后再private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() 加入Intent的receiver动作;

else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
updateIconKeyAction(intent);
}


及处理函数:

private final void updateIconKeyAction(Intent intent){
int     keycode = intent.getIntExtra("keycode", -1);
IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));

if(keycode != -1){
long now = SystemClock.uptimeMillis();

KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0);
KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0);

try {
wm.injectKeyEvent(down, false);
}catch (RemoteException e) {
Log.i("Input", "DeadOjbectException");
}

try{
wm.injectKeyEvent(up, false);
}catch(RemoteException e) {
Log.i("Input", "DeadOjbectException");
}
}
}


3. StatusBar通知栏屏蔽按钮

当拉出expand的通知栏时,按钮的响应非常慢,这时最好将按钮给屏蔽掉,我们在 statusBarView.java中增加两个方法:

public void hiddenHotIcons(){
mHomeBtn.setVisibility(View.INVISIBLE);
mBackBtn.setVisibility(View.INVISIBLE);
mMenuBtn.setVisibility(View.INVISIBLE);
}

public void showHotIcons(){
mHomeBtn.setVisibility(View.VISIBLE);
mBackBtn.setVisibility(View.VISIBLE);
mMenuBtn.setVisibility(View.VISIBLE);
}


拉出或收回通知栏中,就可以调用这个函数来显示或隐藏这几个按钮。

修改文件: statusBarService.java

void performExpand() {
if (SPEW) Log.d(TAG, "performExpand: mExpanded=" + mExpanded);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
return ;
}
if (mExpanded) {
return;
}

// It seems strange to sometimes not expand...
if (false) {
synchronized (mNotificationData) {
if (mNotificationData.size() == 0) {
return;
}
}
}

mExpanded = true;
makeExpandedVisible();
mStatusBarView.hiddenHotIcons(); // Changed!!!
updateExpandedViewPos(EXPANDED_FULL_OPEN);

if (false) postStartTracing();
}

void performCollapse() {
if (SPEW) Log.d(TAG, "performCollapse: mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible);

if (!mExpandedVisible) {
return;
}
mExpandedVisible = false;
panelSlightlyVisible(false);
mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
mExpandedDialog.getWindow().setAttributes(mExpandedParams);
mTrackingView.setVisibility(View.GONE);

mStatusBarView.showHotIcons(); // Changed!!!!
if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
}
setDateViewVisibility(false, com.android.internal.R.anim.fade_out);

if (!mExpanded) {
return;
}
mExpanded = false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: