`
dss16694
  • 浏览: 148399 次
社区版块
存档分类
最新评论

在android的状态栏(statusbar)中增加menu,home和back快捷键的方法

 
阅读更多

原帖地址:http://blog.csdn.net/freshui/article/details/5738115

 

需要说明的是:刚入手android没几天,对系统还不算很熟悉,这篇文章是基于前一篇转帖做的。只是觉得他的方法有些麻烦,而且改出来的效果也不是我想要的。

 

 

由于完全改了status bar,建议先做几张png图片,加到

Frameworks/base/core/res/res/drawable

下。最好做一张背景图,替换 statusbar_background.png

另外我又加了几张icon,分别是home menuback的正常和按下状态。

这些图片为:

stat_home.png

stat_home_pressed.png

stat_back.png

stat_back_pressed.png

stat_menu.png

stat_menu_pressed.png

 

 

修改步骤为:

 

一.    修改xml界面

 

1. 增加图标

 

当然,更改整个status bar避免不要要对源码大刀修一下。我的该法是:

 修改status barlayerout文件:

Frameworks/base/core/res/res/layout/status_bar.xml

在原来的linearlayout中新增三个image view

 

 

  1. <LinearLayout android:id="@+id/icons"  
  2.     android:layout_width="fill_parent"  
  3.     android:layout_height="fill_parent"  
  4.     android:orientation="horizontal">  
  5.   
  6.           <ImageView android:id="@+id/status_home"  
  7.                  android:layout_width="wrap_content"  
  8.                  android:layout_height="wrap_content"  
  9.                  android:layout_gravity="top"  
  10.                  android:paddingTop="6dip"  
  11.                  android:paddingRight="10dip"  
  12.                  android:paddingLeft="10dip"  
  13.                  android:src="@drawable/stat_home" />  
  14.   
  15.     <com.android.server.status.IconMerger android:id="@+id/notificationIcons"  
  16.         android:layout_width="0dip"  
  17.         android:layout_weight="1"  
  18.         android:layout_height="fill_parent"  
  19.         android:layout_alignParentLeft="true"  
  20.         android:paddingLeft="6dip"  
  21.         android:gravity="center_vertical"  
  22.         android:orientation="horizontal"/>    
  23.           
  24.     <LinearLayout android:id="@+id/statusIcons"  
  25.         android:layout_width="wrap_content"  
  26.         android:layout_height="fill_parent"  
  27.         android:layout_alignParentRight="true"  
  28.         android:paddingRight="6dip"  
  29.         android:gravity="center_vertical"  
  30.         android:orientation="horizontal"/>      
  31.   
  32.           <ImageView android:id="@+id/status_menu"  
  33.                  android:layout_width="wrap_content"  
  34.                  android:layout_height="wrap_content"  
  35.                  android:layout_gravity="top"  
  36.                  android:paddingTop="6dip"  
  37.                  android:paddingLeft="10dip"  
  38.                  android:paddingRight="10dip"  
  39.                  android:src="@drawable/stat_menu" />  
  40.   
  41.           <ImageView android:id="@+id/status_back"  
  42.                  android:layout_width="wrap_content"  
  43.                  android:layout_height="wrap_content"  
  44.                  android:layout_gravity="top"  
  45.                  android:paddingTop="6dip"  
  46.                  android:paddingRight="10dip"  
  47.                  android:paddingLeft="10dip"  
  48.                  android:src="@drawable/stat_back" />  
  49.   
  50. /LinearLayout>  
  

 

这样做的好处就是简单。同时保证最右端是home按钮,最左端是back按钮,不受它本来的约束。这样status bar上即可看到这些按钮了。

       图标的位置,可通过修改 paddingRight paddingLeft paddingTop的值达到最佳视觉效果。

 

2. 修改status bar的高度。

 

既然要在status bar上增加那么几个按钮,当然是想要使用触摸操作的,android自带的status bar高度太小,不适用。对于7寸屏的话,50pixel的高度应该是差不多了。

修改高度很简单,如我转的shinning mm的博文。

修改frameworks/base/core/res/res/values/dimens.xmlstatus_bar_height属性

    <!-- Height of the status bar -->

    <dimen name="status_bar_height">50dip</dimen>

当然,如果相改title的高度,可以修改 Frameworks/base/core/res/res/values/themes.xml中的Window attributeswindowTitleSize值,不过我觉得没必要,改了反倒不好看了 :)

 

编译运行一下:

 

 

  1. ~/donut$ source ./env.sh  
  2. ~/donut$ make –j8  
  3. ~/donut$ emulator –skin WVGA800  

 

 

 看状态栏是不是改变了?

 

 

 

 为按钮添加动态效果

 

添加动态效果,就是触摸按下hilight,松开或者移出后恢复的动作。这一块,我是通过修改frameworks/base/services/java/com/android/server/status/StatusBarView.java实现的。

 

1. 获取statusbar中新增加的iconhandler

 

在类中新增加三个成员(这需要import android.widget.ImageView;):

 

 

  1. ImageView mHomeIcon;  
  2. ImageView mBackIcon;  
  3. ImageView mMenuIcon;  
      

 

同时增加三个常量,表示这些icon对应的键值(这需要import android.view.KeyEvent;)

 

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

 

onFinishInflate()中,获得实际的对象:

  1. mHomeIcon = (ImageView)findViewById(R.id.status_home);  
  2. mBackIcon = (ImageView)findViewById(R.id.status_back);  
  3. mMenuIcon = (ImageView)findViewById(R.id.status_menu);  

 

 

 

这三个对象就是我们在status_bar.xml中添加的。

 

2. 添加触摸处理。

首先,应该判断是那个图标被按下,这个我们在StatusBarView.JavaonTouchEvent中来判断。

这里,我做了一个小的按键状态,已方便处理按下、弹起和移出的动作。

首先增加两个状态成员:

 

  1. int mResvKeyState = -1;  //记住的上次按键状态, -1为无状态。  
  2. int mResvKeyCode  = -1;  //记住的上次按键值,-1为无状态。  

            

 

 

 

这样我的onTouchEvent就变成这样了:

 

 

  1. @Override  
  2.    public boolean onTouchEvent(MotionEvent event) {  
  3.     if(mService.mExpanded==true || mService.mTracking==true){  
  4.        if (event.getAction() != MotionEvent.ACTION_DOWN) {  
  5.            mService.interceptTouchEvent(event);  
  6.        }  
  7.         return true;  
  8.     }  
  9.   
  10.     if(mResvKeyState == -1// remembered key state, no reserve  
  11.     {  
  12.         switch(getResvKeyArea(event)){  
  13.             case RESV_KEY_HOME:  
  14.             case RESV_KEY_BACK:  
  15.             case RESV_KEY_MENU:  
  16.             {  
  17.                 mResvKeyState = event.getAction();  
  18.                 mResvKeyCode  = getResvKeyArea(event);  
  19.   
  20.                 updateResvKeyIcon(mResvKeyState, mResvKeyCode);  
  21.             }  
  22.             break;  
  23.               
  24.             default:  
  25.             if (event.getAction() != MotionEvent.ACTION_DOWN) {  
  26.                 mService.interceptTouchEvent(event);  
  27.             }  
  28.         }  
  29.     }else{  
  30.         mResvKeyState = event.getAction(); // new state  
  31.           
  32.         if(mResvKeyState == MotionEvent.ACTION_MOVE){  
  33.             if(mResvKeyCode != getResvKeyArea(event)){  
  34.                 /* out of bound, resume the icon */  
  35.                 updateResvKeyIcon(MotionEvent.ACTION_UP, mResvKeyCode);  
  36.                   
  37.                 mResvKeyCode  = -1;  
  38.                 mResvKeyState = -1;  
  39.             }  
  40.         }else if(mResvKeyState == MotionEvent.ACTION_UP){  
  41.             updateResvKeyIcon(mResvKeyState, mResvKeyCode);  
  42.             mResvKeyCode  = -1;  
  43.             mResvKeyState = -1;  
  44.         }else{  
  45.             Log.d(TAG, "state machine error! Never be here!");  
  46.         }  
  47.     }  
  48.       
  49.        return true;  
  50.    }  

 

里面用到的两个private方法简单实现如下:

 

  1. private int getResvKeyArea(MotionEvent event)  
  2. {  
  3.     if(  (event.getX() <= mHomeIcon.getRight())  
  4.       && (event.getY() <= this.getHeight()) ){  
  5.         return RESV_KEY_HOME;  
  6.     }  
  7.     else if(  (event.getX() >= mBackIcon.getLeft())  
  8.       && (event.getY() <= this.getHeight()) ){  
  9.         return RESV_KEY_BACK;  
  10.     }  
  11.     else if(  (event.getX() >= mMenuIcon.getLeft())  
  12.       && (event.getY() <= this.getHeight()) ){  
  13.         return RESV_KEY_MENU;  
  14.     }else  
  15.         return -1;  
  16. }  
  17.   
  18. private int updateResvKeyIcon(int state, int key)  
  19. {  
  20.     if(key == RESV_KEY_BACK){  
  21.         if(state == MotionEvent.ACTION_UP){  
  22.             mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back);  
  23.         }else if(state == MotionEvent.ACTION_DOWN){  
  24.             mBackIcon.setImageResource(com.android.internal.R.drawable.stat_back_pressed);  
  25.         }  
  26.     }else if(key == RESV_KEY_HOME){  
  27.         if(state == MotionEvent.ACTION_UP){  
  28.             mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home);  
  29.         }else if(state == MotionEvent.ACTION_DOWN){  
  30.             mHomeIcon.setImageResource(com.android.internal.R.drawable.stat_home_pressed);  
  31.         }  
  32.     }else if(key == RESV_KEY_MENU){  
  33.         if(state == MotionEvent.ACTION_UP){  
  34.             mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu);  
  35.         }else if(state == MotionEvent.ACTION_DOWN){  
  36.             mMenuIcon.setImageResource(com.android.internal.R.drawable.stat_menu_pressed);  
  37.         }  
  38.     }  
  39.       
  40.     return 0;  
  41. }  

 

 

同时,我不想再在按下这些icon的时候,触发下拉动作,我也改了onInterceptTouchEvent函数:

 

  1.  @Override  
  2.  public boolean onInterceptTouchEvent(MotionEvent event) {  
  3.     if(  (event.getX() > mHomeIcon.getRight())  
  4.  &&  (event.getX() < mMenuIcon.getLeft())){  
  5.         return mService.interceptTouchEvent(event)  
  6.              ? true : super.onInterceptTouchEvent(event);  
  7.     }  
  8.   
  9.     return false;  
  10. }  

 

 

 

 

 

再编译一下,看一下结果 : 是不是能动了?

 

 

 

三,添加相应事件

 

1. 添加新的intent

首先是新增一条intent framework/base/core/java/android/content/intent.java中增加

 

 

 

 

 

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

 

 

 

2. 发送intent 

  在StatusBarView.java的OnKeyEvent中,松开按键的分支else if(mResvKeyState == MotionEvent.ACTION_UP)操作中加入发送intent的动作:

 

  1. Intent intent = new Intent(Intent.ACTION_ICONKEY_CHANGED);  
  2. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  3. intent.putExtra("keycode",   mResvKeyCode);  
  4. mService.sendIntent(intent);  

 

这个intent是只有注册的接收者才能接收。

 

这里,我们是通过StatusBarService来发送这个intent的。

在StatusBarService.java中新增一个方法:

 

  1. void sendIntent(Intent intent)  
  2. {  
  3.     mContext.sendBroadcast(intent);  
  4. }  

 

 

3.接收并处理intent

这个就要修改StatusBarPolicy.java了

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

  filter.addAction(Intent.ACTION_ICONKEY_CHANGED);

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

 

  1. else if (action.equals(Intent.ACTION_ICONKEY_CHANGED)) {  
  2. G, "Received ACTION_ICONKEY_CHANGED");  
  3.     updateIconKeyAction(intent);  
  4. }  

 

 

方法updateIconKeyAction的定义如下:

 

  1. private final void updateIconKeyAction(Intent intent){  
  2.     int     keycode = intent.getIntExtra("keycode", -1);  
  3.   
  4.     if(keycode != -1){  
  5.         long now = SystemClock.uptimeMillis();  
  6.   
  7.         try {  
  8.             KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0);  
  9.             KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0);  
  10.             (IWindowManager.Stub  
  11.                 .asInterface(ServiceManager.getService("window")))  
  12.                 .injectKeyEvent(down, false);  
  13.             (IWindowManager.Stub  
  14.                 .asInterface(ServiceManager.getService("window")))  
  15.                 .injectKeyEvent(up, false);  
  16.         } catch (RemoteException e) {  
  17.             Log.i("Input""DeadOjbectException");  
  18.         }  
  19.               
  20.     }  
  21. }  

 

 

这样,基本上就完成了。

编译一下, 由于新增了一个intent,因此要先make update-api,

 

  1. ~/donut$ source ./env.sh  
  2. ~/donut$ make update-api  
  3. ~/donut$ make –j8  
  4. ~/donut$ emulator –skin WVGA800  

 

 

 

另外,如果不是做phone,也可以在StatusBarPolicy.java中将所有phone相关的处理都删掉。

 

 

分享到:
评论

相关推荐

    在android的状态栏(statusbar)中增加menu,home和back快捷键的方法

    在android的状态栏(statusbar)中增加menu,home和back快捷键的方法 framework里 修改的

    Android statusBar添加back,home,menu按钮

    在Android系统中,StatusBar是位于屏幕顶部的一条栏,通常显示时间、通知图标以及系统状态信息。在Android 2.3(Gingerbread)版本中,StatusBar默认仅包含一些基本功能,如通知和解锁控件。然而,根据您的标题和...

    对在Android的状态栏添加Menu,Back,Home的改进

    然而,有些开发者希望在状态栏中添加更多的功能快捷键,如Menu、Back和Home键,以提供更便捷的操作方式。本文将详细介绍如何实现这一功能,并解决在实现过程中遇到的问题。 首先,要在状态栏添加Menu、Back、Home三...

    Android4.4之后改变状态栏statusbar背景色

    在Android开发中,自4.4版本(KitKat)开始,系统引入了透明状态栏(Translucent Status Bar)的功能,允许应用的内容延伸到状态栏下方,提供了更沉浸式的用户体验。这个特性同时也带来了自定义状态栏颜色的需求。...

    iOS 自定义视图覆盖状态栏StatusBar

    在iOS开发中,状态栏(StatusBar)是显示时间、网络信号、电量等系统信息的区域。自定义状态栏可以为应用程序增添独特的视觉效果,提升用户体验。本教程将深入讲解如何在不隐藏状态栏的情况下,利用UIWindow视图来...

    Android-gm-statusbar状态栏透明工具类

    在`icuihai-gm-statusbar-2a8f406`这个压缩包中,很可能是包含了这个状态栏透明工具类的源代码,通过查看源码,开发者可以了解到具体的实现方法和细节,甚至可以根据自己的需求进行二次开发和定制。通常,源码会包含...

    wpf 状态栏 右下角三角statusbar

    在Windows Presentation Foundation(WPF)中,状态栏(StatusBar)是一种常见的用户界面元素,用于显示应用程序的状态信息或者提示用户的相关消息。"右下角三角"通常指的是在状态栏中添加了一个可以折叠或展开的...

    android 禁用statusBar demo

    在Android开发中,有时我们可能需要为特定场景禁用状态栏(StatusBar),比如为了实现全屏体验或特殊界面设计。然而,通常情况下,系统权限是不允许应用直接禁用statusBar的,尤其是对于没有获取到SYSTEM_ALERT_...

    Unity3D Android 状态栏

    本文将深入探讨如何在Unity3D 5.3.4版本中实现在Android 2.0系统上显示状态栏和虚拟按键,并支持沉浸式透明效果。 首先,我们需要理解Android的状态栏和虚拟按键。状态栏是位于屏幕顶部,显示系统时间和通知的地方...

    Android编程实现禁止StatusBar下拉的方法

    本文实例讲述了Android编程实现禁止StatusBar下拉的方法。分享给大家供大家参考,具体如下: Android中有许多隐藏的Service,StatusBarManager就是其中一个,在Context.java中可以看到: /** * Use with {@link #...

    android修改状态栏背景颜色、字体颜色,隐藏状态栏,状态栏透明

    在Android开发中,状态栏是屏幕顶部显示时间、网络连接、电量等信息的区域,它的样式和行为可以被开发者自定义以实现特定的界面效果。本教程将详细讲解如何修改状态栏的背景颜色、字体颜色,如何隐藏状态栏以及如何...

    Android自定义状态栏颜色与应用标题栏颜色一致

    在Android开发中,为了让应用的用户体验更加统一和美观,有时我们需要自定义状态栏的颜色,使其与应用的标题栏颜色保持一致。在iOS系统中,这种效果很常见,但早期的Android版本并不支持这一特性。不过,从Android ...

    android状态栏一体化,沉浸式状态栏,状态栏管理类

    在Android开发中,状态栏(StatusBar)是用户界面不可或缺的一部分,它显示了设备的状态信息,如时间、电量、网络连接等。"android状态栏一体化,沉浸式状态栏,状态栏管理类"是一个重要的主题,主要涉及到如何使...

    Android 沉浸式状态栏(亲测好用)

    在Android开发中,沉浸式状态栏(Immersive Status Bar)是一种常见的设计手法,它能够使应用的内容无缝地延伸到状态栏下方,提供更全面、更沉浸的用户体验。这种技术尤其在游戏和全屏应用中非常受欢迎,因为它最大...

    Android系统控制状态栏下拉

    在Android系统中,状态栏是显示系统通知和时间等信息的重要区域,而下拉状态栏则通常用于展开快捷设置和查看详细的通知。本篇将详细探讨如何通过编程方式,特别是利用反射机制来控制Android状态栏的下拉行为。 首先...

    Android 沉浸式状态栏的实现方法、状态栏透明的实现方法

    在Android开发中,沉浸式状态栏(也称为透明状态栏)是一种流行的设计趋势,它能够为应用程序提供更统一、无边界的视觉体验。沉浸式状态栏允许应用内容延伸到状态栏下,使得整个屏幕看起来更加一体化。下面我们将...

    StatusBar定制iphone状态栏

    在iOS开发中,状态栏(StatusBar)是位于应用程序顶部,显示时间、网络连接状态、电量等信息的小区域。默认情况下,iOS系统会自动处理状态栏的样式和内容,但有时开发者可能需要对其进行自定义,以适应特定应用的...

    android状态栏显示

    在Android开发中,状态栏(StatusBar)是用户界面不可或缺的一部分,它显示了系统时间、电池状态、网络连接等重要信息。有时候,开发者需要对状态栏进行定制,例如改变颜色、图标或者隐藏/显示状态栏,以实现特定的...

    Android有效获取状态栏(StatusBar)高度的方法

    在Android应用开发中,有时我们需要根据界面需求对状态栏(StatusBar)进行自定义处理,比如全屏显示或者在状态栏下方添加特殊的背景色。这时,了解如何有效地获取状态栏高度就显得尤为重要。本文将详细讲解如何在...

Global site tag (gtag.js) - Google Analytics