上一篇文章中談到的加入快捷按鈕的方法,實(shí)際上還是太過(guò)麻煩。那篇博客是在我剛接觸android源代碼沒(méi)幾天時(shí),參考網(wǎng)上的介紹方法,自己看了下源代碼嘗試著寫(xiě)了一個(gè)。 不過(guò)那個(gè)方法,是我直接用貼圖的方法實(shí)現(xiàn)了按鈕特效,這實(shí)在是太浪費(fèi)了,最近一直仍有朋友問(wèn)我那篇文章中的問(wèn)題,我想還是重寫(xiě)一下,用一個(gè)更簡(jiǎn)單點(diǎn)的方法,直接使用android的ImageButton控件,通過(guò)其OnTouchListener方法操作即可,Button的高亮與否完全由系統(tǒng)處理,這樣也不會(huì)出現(xiàn)button高亮不消失的bug。以下方法在android 2.1 上編譯調(diào)試通過(guò)
1。 準(zhǔn)備資源,修改XML文件
和上篇文章一樣,準(zhǔn)備幾張圖,這里我們準(zhǔn)備添加home back和menu圖標(biāo),就需要準(zhǔn)備6張圖,三張普通狀態(tài),三張按下的高亮狀態(tài)圖標(biāo):
stat_home.png
stat_home_pressed.png
stat_back.png
stat_back_pressed.png
stat_menu.png
stat_menu_pressed.png
同時(shí),在 Frameworks/base/core/res/res/drawable下創(chuàng)建三個(gè)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,如下:
如上篇,修改statusbar的高度,編譯一下,即可看到效果。
2。 添加按鈕的動(dòng)作效果
在statusBarView.java中,活的button的handler
類中新增加三個(gè)成員:
- ImageButton mHomeBtn;
- ImageButton mBackBtn;
- ImageButton mMenuBtn;
增加三個(gè)常量:
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中,獲取幾個(gè)button 的handler,并設(shè)置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(){
-
- public boolean onTouch(View v, MotionEvent event)
- {
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_HOME);
- }
- break;
- }
- return false;
- }
- };
-
- private OnTouchListener backOnTouch = new OnTouchListener(){
-
- public boolean onTouch(View v, MotionEvent event)
- {
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_BACK);
- }
- break;
- }
- return false;
- }
- };
-
- private OnTouchListener menuOnTouch = new OnTouchListener(){
-
- public boolean onTouch(View v, MotionEvent event)
- {
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- {
- sendKeyIntent(RESV_KEY_MENU);
- }
- break;
- }
- return false;
- }
- };
也就是簡(jiǎn)單的廣播一個(gè)intent消息給statusBarPolicy處理。
為防止點(diǎn)擊statusBar上的按鈕, 觸發(fā)標(biāo)題欄的expend事件, 修改一下函數(shù)onInterceptTouchEvent,點(diǎn)擊到不屬于button區(qū)域時(shí)才允許解析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;
-
-
- }
- }
修改StatusBarService.java,發(fā)送Intent消息需要content,這個(gè)目前只能在StatusBarService中添加一個(gè)方法:
- void sendIntent(Intent intent)
- {
- mContext.sendBroadcast(intent);
- }
要發(fā)送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
這個(gè)就要修改StatusBarPolicy.java了
首先,在構(gòu)造函數(shù)中加入Intent的filter,注冊(cè)號(hào)這個(gè)intent的receiver。
- filter.addAction(Intent.ACTION_ICONKEY_CHANGED);
然后再private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() 加入Intent的receiver動(dòng)作;
- else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {
- Log.d(TAG, "Received ACTION_ICONKEY_CHANGED");
- updateIconKeyAction(intent);
- }
及處理函數(shù):
- 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通知欄屏蔽按鈕
當(dāng)拉出expand的通知欄時(shí),按鈕的響應(yīng)非常慢,這時(shí)最好將按鈕給屏蔽掉,我們?cè)?statusBarView.java中增加兩個(gè)方法:
- 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);
- }
拉出或收回通知欄中,就可以調(diào)用這個(gè)函數(shù)來(lái)顯示或隱藏這幾個(gè)按鈕。
修改文件: statusBarService.java
- void performExpand() {
- if (SPEW) Log.d(TAG, "performExpand: mExpanded=" + mExpanded);
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return ;
- }
- if (mExpanded) {
- return;
- }
-
-
- if (false) {
- synchronized (mNotificationData) {
- if (mNotificationData.size() == 0) {
- return;
- }
- }
- }
-
- mExpanded = true;
- makeExpandedVisible();
- mStatusBarView.hiddenHotIcons();
- 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();
- 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;
- }