Android ActionBar 兼容2.x注意细节

来源:互联网 发布:超级碧业生 知乎 编辑:程序博客网 时间:2024/05/22 14:27


参考:

   http://www.bubuko.com/infodetail-659967.html      (android2.x使用ActionBar的总结)

  http://iteches.com/archives/63816   (【ANDROID】启用 SUPPORT LIBRARY 的 ACTIONBAR)




1.设置ActionBar标题栏的返回按钮和图标

ActionBar bar=getSupportActionBar();//ActivityUitl.setHome(bar, R.drawable.huifui);getSupportActionBar().setDisplayShowHomeEnabled(true);getSupportActionBar().setIcon(R.drawable.ic_launcher);//只能代码设置图标了。bar.setDisplayHomeAsUpEnabled(true);//设置返回箭头setOverflowShowingAlway();


2.设置标题栏各item(图标、显示overflow)

 Android 新建activity 时默认会给每个Activity生成对应的menu文件,详情如下代码:


<menu xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    tools:context="com.example.antest.MainActivity" >       <item        android:id="@+id/action_settings"        android:orderInCategory="100"        android:title="@string/action_settings"        app:showAsAction="never"/><!-- Android 3.0以下,就算设置never也不显示overflow,需要在代码里设置 -->    <item         android:id="@+id/write"        android:title="写邮件"        android:icon="@drawable/ic_launcher"        android:showAsAction="never"/><!-- 设置了图标 -->    <item         android:id="@+id/action_search"        android:title="搜索"        app:showAsAction="always"        app:actionViewClass="android.support.v7.widget.SearchView"        />    <!--        为兼容android 3.0以下的版本出现搜索按钮和搜索框(说白了就是兼容android 3.0以下使用ActionBar)       需要添加命名空间xmlns:app="http://schemas.android.com/apk/res-auto",若没有该命名空间,自己添加上。       同时,在<item>上引用该命名空间,如搜索app:actionViewClass="android.support.v7.widget.SearchView"    下同!     -->          <item         android:id="@+id/action_share"         app:actionProviderClass="android.support.v7.widget.ShareActionProvider"         app:showAsAction="always"         android:title="分享" />     </menu>

注意命名空间: xmlns:app="http://schemas.android.com/apk/res-auto"以及它的使用


重写onCreateOptionsMenu,实现分享按钮

@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);MenuItem shareItem = menu.findItem(R.id.action_share);ShareActionProvider provider=new ShareActionProvider(MainActivity.this);provider.setShareIntent(getDefaultIntent());return super.onCreateOptionsMenu(menu);/* * 为兼容android 3.0以下版本,获取shareActionProvider需要获取android.support.v7.widget.ShareActionProvider的 * 然而,若不考虑android 3.0以下版本,则获取为: *  MenuItem shareItem = menu.findItem(R.id.action_share);    ShareActionProvider provider = (ShareActionProvider) shareItem.getActionProvider();    provider.setShareIntent(getDefaultIntent()); */}private Intent getDefaultIntent() {Intent intent = new Intent(Intent.ACTION_SEND);intent.setType("image/*");return intent;}



3.通过代码设置显示overflow

   Android 3.0以下的overflow是通过物理菜单键显示的。

/** * 使Android 3.0以下overflow显示(兼容) */private void setOverflowShowingAlway(){   try{        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){   // android3.0以后的版本才存在sHasPermanentMenuKey属性            ViewConfiguration config = ViewConfiguration.get(this);            Field menuKeyField = ViewConfiguration.class                    .getDeclaredField("sHasPermanentMenuKey");            menuKeyField.setAccessible(true);            menuKeyField.setBoolean(config, false);        } else {            // 获取actionBarView android.support.v7.internal.widget.ActionBarView        ActionBarView actionBarView=(ActionBarView)findViewById(android.support.v7.appcompat.R.id.action_bar);            MenuPresenter.Callback menuCallback = new MenuPresenter.Callback() {                                 @Override                public boolean onOpenSubMenu(MenuBuilder subMenu) {                    android.view.Window.Callback cb = getWindow().getCallback();                    if (cb != null) {                        cb.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu);                        return true;                    }                    return false;                }                                 @Override                public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {                    closeOptionsMenu();                }            };                         Field menuPresenterField = actionBarView.getClass().getSuperclass().getDeclaredField("mActionMenuPresenter");            menuPresenterField.setAccessible(true);            final ActionMenuPresenter menuPresenter = new ActionMenuPresenter(this);            menuPresenter.setReserveOverflow(true);  // 这句是关键,设置overflow可见            menuPresenter.setCallback(menuCallback);            menuPresenter.setId(android.support.v7.appcompat.R.id.action_menu_presenter);            // 修改actionBarView.mActionMenuPresenter=menuPresenter;            menuPresenterField.set(actionBarView, menuPresenter);                         Field expandedMenuPresenterField = actionBarView.getClass().getDeclaredField("mExpandedMenuPresenter");            expandedMenuPresenterField.setAccessible(true);            Constructor contructor = Class.forName("android.support.v7.internal.widget.ActionBarView$ExpandedActionViewMenuPresenter").getDeclaredConstructor(actionBarView.getClass());            contructor.setAccessible(true);            Object expandedMenuPresenter = contructor.newInstance(actionBarView);            // 修改actionBarView.mExpandedMenuPresenter=expandedMenuPresenter;            expandedMenuPresenterField.set(actionBarView, expandedMenuPresenter);        }    } catch(Exception e){    Log.e("kong", e.getMessage(), e);    }


4.通过代码设置item的图标显示(兼容2.x)

     


     

/** * onMenuOpened触发时传入Menu对象,通过反射设置字段setOptionalIconsVisible显示icon * @param menu */private void setOptionalIconsVisible(Menu menu){if(menu == null) return;if(!menu.getClass().getSimpleName().equals("MenuBuilder")) return;try {              Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);              m.setAccessible(true);              m.invoke(menu, true);          } catch (Exception e) {          } }/** * overflow按钮去查看隐藏的Action按钮,你会发现这部分Action按钮都是只显示文字不显示图标的,这是官方的默认效果, * Google认为隐藏在overflow中的Action按钮都应该只显示文字,其实,overflow中的Action按钮应不应该显示图标, * 是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的,如果我们在overflow被展开的时候给这个 * 方法传入true,那么里面的每一个Action按钮对应的图标就都会显示出来了 */@Override  public boolean onMenuOpened(int featureId, Menu menu) { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){   // android3.0以后的版本,参数menu不为空,直接通过反射方法修改setOptionalIconsVisible的值if(featureId == Window.FEATURE_ACTION_BAR){setOptionalIconsVisible(menu);}    return super.onMenuOpened(featureId, menu);  } else {ActionBarView actionBarView = (ActionBarView) findViewById(android.support.v7.appcompat.R.id.action_bar);// 通过点击overflowButton时,传入的参数featureId为FEATURE_ACTION_BAR,而通过点击menu按键,传入的参数featureId为FEATURE_OPTIONS_PANELif(featureId == Window.FEATURE_ACTION_BAR){   // android3.0之前的版本,由于phonewindow的机制,导致传进的menu是空的,需要把menu赋值为ActionMenuPresenter.mMenuif(menu == null){try{Field menuPresenterField = actionBarView.getClass().getSuperclass().getDeclaredField("mActionMenuPresenter");menuPresenterField.setAccessible(true);ActionMenuPresenter menuPresenter = (ActionMenuPresenter) menuPresenterField.get(actionBarView);Field menuField = BaseMenuPresenter.class.getDeclaredField("mMenu");menuField.setAccessible(true);menu = (Menu) menuField.get(menuPresenter);} catch(Exception e){e.printStackTrace();}}setOptionalIconsVisible(menu);    return super.onMenuOpened(featureId, menu);  } else {actionBarView.showOverflowMenu();  // 把下拉菜单显示到ActionBar上return false;}}} 

PS :

 以上代码需要用到android-support-v7-appcompat.jar 该包,特别

android.support.v7.internal.widget.ActionBarView  这个类。
但是问题出现了,目前2015-4-20日,更新的Android sdk 版本为api-22,Extras--->Android Support Library 支持库版本为version-22,也就是生成的依赖库的。但是在该高版本的包,找不到以上的ActionBarView 类,

,从图上可以看到,导致此次建立项目最高建立到Android 4.4  (Android_2.2~4.4),可能Android Support Library_22删除了ActionBarView或换了其他实现方法。若大家研究出来,请告知一下,谢谢您的无私。






以下贴出原文内容:


好久没有在csdn上写博客了,最近闲来无事,决定仿微信界面做几个东西,原本以为挺简单的事情,结果折腾了好久才把第一步的ActionBar搞定,其中过程可谓坎坷之极,记录下来,以便给各位分享。

首先介绍一下我的手机,我的手机是android2.3.4的系统,要使用ActionBar,有两种选择,一个是使用大名鼎鼎的开源组件:ActionBarSherlock;一个是使用google自己出的android-support-v7包;ActionBarSherlock自从google推出android-support-v7包以后,基本上要退出历史舞台了,因此我决定使用android-support-v7一试。

首先下载android-support-v7-appcompat(包括jar包和资源项目),新建项目weixin(注意最低sdk版本要求),引入android-support-v7-appcompat.jar(把该jar包放到lib目录下,刷新工程),并把android-support-v7-appcompat资源项目作为类库引入到项目中,项目结果如下

技术分享

新建MainActivity,继承类android.support.v7.app.ActionBarActivity,代码如下:

package com.example.weixin;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.Menu;public class MainActivity extends ActionBarActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}}
修改res\values\styles.xml,使用androi-support-v7的Theme.AppCompat.Light.DarkActionBar风格,如下

<<span id="25_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="25_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="25" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>ources>    <!--        Base application theme, dependent on API level. This theme is replaced        by AppBaseTheme from res/values-vXX/<span id="26_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="26_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=style&k0=style&kdi0=0&luki=6&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="26" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">style</span></a></span>s.xml on newer devices.    -->    <style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar"</<span id="27_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="27_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=span&k0=span&kdi0=0&luki=4&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="27" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">span</span></a></span>>>        <!--            Theme customizations available in newer API levels can go in            res/values-vXX/styles.xml, while customizations related to            backward-compatibility can go here.        -->    </style>    <!-- Application theme. -->    <style name="AppTheme" parent="AppBaseTheme">        <!-- All customizations that are NOT specific to a particular API-level can go here. -->    </<span id="28_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="28_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=style&k0=style&kdi0=0&luki=6&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="28" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">style</span></a></span>></<span id="29_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="29_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="29" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>ources>
修改res\menu\main.xml,如下:

<menu xmlns:android="http://schemas.android.com/apk/<span id="18_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="18_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="18" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>/android"      xmlns:<span id="19_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="19_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=alpha&k0=alpha&kdi0=0&luki=10&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="19" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">alpha</span></a></span>="http://schemas.android.com/apk/res-auto">    <!--android.widget.SearchView在<span id="20_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="20_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=api&k0=api&kdi0=0&luki=8&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="20" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">api</span></a></span>11之前不存在,需要使用 android.support.v7.widget.SearchView-->    <item        android:id="@+id/action_search"        alpha:actionViewClass="android.support.v7.widget.SearchView"        android:actionProviderClass=""        android:icon="@drawable/actionbar_search_icon"        alpha:showAsAction="ifRoom|collapseActionView"        android:title="@string/action_search"/>        <item        android:id="@+id/action_<span id="21_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="21_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=group&k0=group&kdi0=0&luki=3&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="21" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">group</span></a></span>chat"        android:icon="@drawable/ofm_group_chat_icon"        <span id="22_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="22_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=alpha&k0=alpha&kdi0=0&luki=10&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="22" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">alpha</span></a></span>:showAsAction="never"        android:title="@string/action_groupchat"/>    <item        android:id="@+id/action_<span id="23_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="23_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=add&k0=add&kdi0=0&luki=2&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="23" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">add</span></a></span>friend"        android:icon="@drawable/ofm_add_icon"        alpha:showAsAction="never"        android:title="@string/action_addfriend"/>    <item        android:id="@+id/action_scanqrcode"        android:icon="@drawable/ofm_qrcode_icon"        alpha:showAsAction="never"        android:title="@string/action_scanqrcode"/>    <item        android:id="@+id/action_feedback"        android:icon="@drawable/ofm_feedback_icon"        <span id="24_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="24_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=alpha&k0=alpha&kdi0=0&luki=10&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="24" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">alpha</span></a></span>:showAsAction="never"        android:title="@string/action_feedback"/>            </menu>


解析一下,由于android3.0之前,并没有showAsAction、actionProviderClass和actionViewClass等属性,因此需要引入命名空间:xmlns:xxx="http://schemas.android.com/apk/res-auto",使用android-support-v7-appcompat包的属性,因此后面的menuitem的统一使用xxx:showAsAction、xxx:actionProviderClass和xxx:actionViewClass而不是android:showAsAction、android:actionProviderClass和android:actionViewClass;另外搜索按钮的actionViewClass,在android3.0以后可以使用android.widget.SearchView,但在android3.0之前该类并不存在,需要使用android.support.v7.widget.SearchView

经过这样设置以后,按理来说就应该可以了,我们在android2.3环境下运行试试

android2.3运行效果:

 技术分享

发现ActionBar没有overflow按钮,点击物理menu键在下面出现了上下文菜单,这并不是我们想要的效果,查看android doc可知,overflow按钮的显示情况和手机的硬件情况是有关系的,如果手机没有物理Menu键的话,overflow按钮就可以显示, 如果有物理Menu键的话,overflow按钮就不会显示出来,要改变这个默认行为,在ViewConfiguration这个类中, 有一个叫做sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手机有没有物理Menu键的。当然这是一个内部变量,我们无法直接访问它,但是可以通过反射的方式修改它的值,让它永远为false就可以了。在MainActivity中增加方法

private void setOverflowShowingAlway(){try{ViewConfiguration config = ViewConfiguration.get(this);Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");menuKeyField.setAccessible(true);menuKeyField.setBoolean(config, false);}catch(Exception e){e.printStackTrace();}}
并在onCreate(Bundle savedInstanceState)方法中调用

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setOverflowShowingAlway();}

重新运行,发现在android4.0环境下,出现了overflow按钮了,并且按物理menu键也显示正常,只是显示的菜单中只有文字,而没有显示图标,这是官方的默认效果,Google认为隐藏在overflow中的Action按钮都应该只显示文字,其实,overflow中的Action按钮应不应该显示图标,是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的,如果我们在overflow被展开的时候给这个方法传入true,那么里面的每一个Action按钮对应的图标就都会显示出来了,继续在MainActivity中增加方法

  private void setOptionalIconsVisible(Menu menu){if(menu == null) return;if(!menu.getClass().getSimpleName().equals("MenuBuilder")) return;try {              Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);              m.setAccessible(true);              m.invoke(menu, true);          } catch (Exception e) {          } }@Override  public boolean onMenuOpened(int featureId, Menu menu) { if(featureId == Window.FEATURE_ACTION_BAR){setOptionalIconsVisible(menu);}    return super.onMenuOpened(featureId, menu); }

重新运行,发现android4.0环境下已经运行正常了,运行效果如下:

技术分享

正在高兴之余,打开android2.3环境下运行,发现android2.3环境并没有任何变化,overflow按钮没有出来,且按下物理menu键以后再下面出现了上下文菜单,在logcat中出现以下错误:

03-06 13:57:51.587: W/System.err(328): java.lang.NoSuchFieldException: sHasPermanentMenuKey03-06 13:57:51.606: W/System.err(328): at java.lang.ClassCache.findFieldByName(ClassCache.java:446)03-06 13:57:51.616: W/System.err(328): at java.lang.Class.getDeclaredField(Class.java:666)03-06 13:57:51.626: W/System.err(328): at com.example.weixin.MainActivity.setOverflowShowingAlway(MainActivity.java:32)03-06 13:57:51.636: W/System.err(328): at com.example.weixin.MainActivity.onCreate(MainActivity.java:19)03-06 13:57:51.636: W/System.err(328): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)03-06 13:57:51.647: W/System.err(328): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)03-06 13:57:51.656: W/System.err(328): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)03-06 13:57:51.656: W/System.err(328): at android.app.ActivityThread.access$1500(ActivityThread.java:117)03-06 13:57:51.667: W/System.err(328): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)03-06 13:57:51.676: W/System.err(328): at android.os.Handler.dispatchMessage(Handler.java:99)03-06 13:57:51.696: W/System.err(328): at android.os.Looper.loop(Looper.java:123)03-06 13:57:51.707: W/System.err(328): at android.app.ActivityThread.main(ActivityThread.java:3647)03-06 13:57:51.717: W/System.err(328): at java.lang.reflect.Method.invokeNative(Native Method)03-06 13:57:51.736: W/System.err(328): at java.lang.reflect.Method.invoke(Method.java:507)03-06 13:57:51.746: W/System.err(328): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)03-06 13:57:51.756: W/System.err(328): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)03-06 13:57:51.756: W/System.err(328): at dalvik.system.NativeStart.main(Native Method)

在ViewConfiguration没有找到sHasPermanentMenuKey这个类成员!原来android3.0之前,ViewConfiguration并没有sHasPermanentMenuKey这个类成员,怎么办呢?不管度娘还是google,都找不到这个错误的解决办法,只能从sdk的源代码中跟踪了。

首先查找android4.0版本中看看在哪使用了ViewConfiguration.hasPermanentMenuKey()方法,经过分析是在类com.android.internal.view.ActionBarPolicy中的showsOverflowMenuButton()使用了,代码如下:

    public boolean showsOverflowMenuButton() {        return !ViewConfiguration.get(mContext).hasPermanentMenuKey();    }

类ActionBarPolicy的方法showsOverflowMenuButton()又在哪被使用了呢?原来是在类com.android.internal.view.menu.ActionMenuPresenter的方法initForMenu(Context context, MenuBuilder menu)中使用了

    @Override    public void initForMenu(Context context, MenuBuilder menu) {        super.initForMenu(context, menu);        final Resources res = context.getResources();        final ActionBarPolicy abp = ActionBarPolicy.get(context);        if (!mReserveOverflowSet) {            mReserveOverflow = abp.showsOverflowMenuButton();        }        if (!mWidthLimitSet) {            mWidthLimit = abp.getEmbeddedMenuWidthLimit();        }        // Measure for initial configuration        if (!mMaxItemsSet) {            mMaxItems = abp.getMaxActionButtons();        }        int width = mWidthLimit;        if (mReserveOverflow) {            if (mOverflowButton == null) {    // 创建overflow按钮                mOverflowButton = new OverflowMenuButton(mSystemContext);                final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);                mOverflowButton.measure(spec, spec);            }            width -= mOverflowButton.getMeasuredWidth();        } else {            mOverflowButton = null;        }        mActionItemWidthLimit = width;        mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * <span id="17_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="17_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="17" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>.getDisplayMetrics().density);        // Drop a scrap view as it may no longer reflect the proper context/config.        mScrapActionButtonView = null;    }
原来在ActionBarMenu初始化时,是根据showsOverflowMenuButton()的返回结果来决定是否创建overflow按钮的,而在android-support-v7-appcompat中也有类ActionBarPolicy和ActionMenuPresenter,其中类ActionMenuPresenter的initForMenu方法与android4.0版本代码差不多,但是类ActionBarPolicy的showsOverflowMenuButton()代码却如下:

  public boolean showsOverflowMenuButton()  {    return Build.VERSION.SDK_INT >= 11;  }
判断sdk的版本大于11(版本大于android3.0)即返回true,否则返回false。看来通过反射方法修改类ActionBarPolicy的showsOverflowMenuButton()返回值是不太可能了,继续往下分析,查看一下类ActionMenuPresenter的initForMenu方法在哪被调用了,结果分析,原来是在类android.support.v7.internal.widget.ActionBarView的configPresenters(MenuBuilder builder)方法中调用的,而configPresenters方法又是在setMenu(SupportMenu menu, MenuPresenter.Callback cb)中调用的,源代码如下:
    public void setMenu(Menu menu, MenuPresenter.Callback cb) {        if (menu == mOptionsMenu) return;        if (mOptionsMenu != null) {            mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);            mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter);        }        MenuBuilder builder = (MenuBuilder) menu;        mOptionsMenu = builder;        if (mMenuView != null) {            final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();            if (oldParent != null) {                oldParent.removeView(mMenuView);            }        }        if (mActionMenuP<span id="8_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="8_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="8" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter == null) {            mActionMenuPresenter = new ActionMenuPresenter(mContext);            mActionMenuPresenter.setCallback(cb);            mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);            mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();        }        ActionMenuView menuView;        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,                LayoutParams.MATCH_PARENT);        if (!mSplitActionBar) {            mActionMenuP<span id="9_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="9_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="9" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter.setExpandedActionViewsExclusive(                    getResources().getBoolean(                    com.android.internal.R.bool.action_bar_expanded_action_views_exclusive));            configPresenters(builder);            menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);            final ViewGroup oldParent = (ViewGroup) menuView.getParent();            if (oldParent != null && oldParent != this) {                oldParent.removeView(menuView);            }            <span id="10_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="10_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=add&k0=add&kdi0=0&luki=2&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="10" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">add</span></a></span>View(menuView, layoutParams);        } else {            mActionMenuP<span id="11_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="11_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="11" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter.setExpandedActionViewsExclusive(false);            // Allow full screen width in split mode.            mActionMenuPresenter.setWidthLimit(                    getContext().getResources().getDisplayMetrics().widthPixels, true);            // No limit to the item count; use whatever will fit.            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);            // Span the whole width            layoutParams.width = LayoutParams.MATCH_PARENT;            configP<span id="12_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="12_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="12" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enters(builder);            menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);            if (mSplitView != null) {                final ViewGroup oldParent = (ViewGroup) menuView.getParent();                if (oldParent != null && oldParent != mSplitView) {                    oldParent.removeView(menuView);                }                menuView.setVisibility(getAnimatedVisibility());                mSplitView.<span id="13_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="13_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=add&k0=add&kdi0=0&luki=2&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="13" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">add</span></a></span>View(menuView, layoutParams);            } else {                // We'll add this later if we missed it this time.                menuView.setLayoutParams(layoutParams);            }        }        mMenuView = menuView;    }    private void configP<span id="14_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="14_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="14" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enters(MenuBuilder builder) {        if (builder != null) {            builder.addMenuPresenter(mActionMenuPresenter);            builder.<span id="15_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="15_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=add&k0=add&kdi0=0&luki=2&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="15" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">add</span></a></span>MenuPresenter(mExpandedMenuPresenter);        } else {            mActionMenuPresenter.initForMenu(mContext, null);            mExpandedMenuPresenter.initForMenu(mContext, null);            mActionMenuPresenter.updateMenuView(true);            mExpandedMenuP<span id="16_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="16_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="16" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter.updateMenuView(true);        }    }

看红字加粗部分,这是实例化ActionMenuPresenter方法的过程,原来如此!我们只要把ActionBarView中修改mActionMenuPresenter的值即可,废话少说,修改MainActivity的setOverflowShowingAlway()方法如下:

private void setOverflowShowingAlway(){try{if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){   // android3.0以后的版本才存在sHasPermanentMenuKey属性ViewConfiguration config = ViewConfiguration.get(this);Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");menuKeyField.setAccessible(true);menuKeyField.setBoolean(config, false);} else {// 获取actionBarView final ActionBarView actionBarView = (ActionBarView) findViewById(android.support.v7.appcompat.R.id.action_bar);MenuP<span id="3_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="3_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="3" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter.Callback menuCallback = new MenuPresenter.Callback() {@Overridepublic boolean onOpenSubMenu(MenuBuilder subMenu) {android.view.Window.Callback cb = getWindow().getCallback();            if (cb != null) {                cb.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu);                return true;            }            return false;}@Overridepublic void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {closeOptionsMenu();}};Field menuP<span id="4_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="4_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="4" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enterField = actionBarView.getClass().getSuperclass().getDeclaredField("mActionMenuPresenter");menuPresenterField.setAccessible(true);final ActionMenuPresenter menuPresenter = new ActionMenuPresenter(this);menuPresenter.setReserveOverflow(true);  // 这句是关键,设置overflow可见menuPresenter.setCallback(menuCallback);menuPresenter.setId(android.support.v7.appcompat.R.id.action_menu_p<span id="5_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="5_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="5" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter);// 修改actionBarView.mActionMenuPresenter=menuPresenter;menuPresenterField.set(actionBarView, menuPresenter);Field expandedMenuPresenterField = actionBarView.getClass().getDeclaredField("mExpandedMenuPresenter");expandedMenuPresenterField.setAccessible(true);Constructor contructor = Class.forName("android.support.v7.internal.widget.ActionBarView$ExpandedActionViewMenuP<span id="6_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="6_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="6" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter").getDeclaredConstructor(actionBarView.getClass());contructor.setAccessible(true);Object expandedMenuPresenter = contructor.newInstance(actionBarView);// 修改actionBarView.mExpandedMenuPresenter=expandedMenuPresenter;expandedMenuPresenterField.set(actionBarView, expandedMenuPresenter);}} catch(Exception e){e.printStackTrace();}}

以上代码首先判断sdk版本是否是android3.0之后的版本,如果是则直接反射修改ViewConfiguration的sHasPermanentMenuKey的值;否则查找出ActionBarView,替换该对象的mActionMenuPresenter及mExpandedMenuPresenter的值,其中mActionMenuPresenter需要设置setReserveOverflow(true),也就是ActionMenuPresenter的mReserveOverflow=true,mReserveOverflowSet=true,这样就能保证程序在运行到ActionMenuPresenter的initForMenu方法时,不z再获取ActionBarPolicy的showsOverflowMenuButton()的返回值作为判断是否增加overflow按钮的依据。

重新运行,呵呵,overflow按钮可以出来了,点击overflow按钮也出现了下来菜单,但是菜单只有文字没有显示图标,并且按物理menu键菜单还是显示在下边。经过分析,原来是android3.0之前的类com.android.internal.policy.impl.PhoneWindow并没有任何ActionBar的代码,而在android3.0以后的版本中增加了不少ActionBar代码,修改MainActivity的onMenuOpened(int featureId, Menu menu)方法如下:

@Override  public boolean onMenuOpened(int featureId, Menu menu) { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){   // android3.0以后的版本,参数menu不为空,直接通过反射方法修改setOptionalIconsVisible的值if(featureId == Window.FEATURE_ACTION_BAR){setOptionalIconsVisible(menu);}    return super.onMenuOpened(featureId, menu);  } else {ActionBarView actionBarView = (ActionBarView) findViewById(android.support.v7.appcompat.R.id.action_bar);// 通过点击overflowButton时,传入的参数featureId为FEATURE_ACTION_BAR,而通过点击menu按键,传入的参数featureId为FEATURE_OPTIONS_PANELif(featureId == Window.FEATURE_ACTION_BAR){   // android3.0之前的版本,由于phonewindow的机制,导致传进的menu是空的,需要把menu赋值为ActionMenuP<span id="0_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="0_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="0" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter.mMenuif(menu == null){try{Field menuPresenterField = actionBarView.getClass().getSuperclass().getDeclaredField("mActionMenuPresenter");menuPresenterField.setAccessible(true);ActionMenuPresenter menuPresenter = (ActionMenuPresenter) menuPresenterField.get(actionBarView);Field menuField = BaseMenuPresenter.class.getDeclaredField("mMenu");menuField.setAccessible(true);menu = (Menu) menuField.get(menuP<span id="1_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="1_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=1001&ch=0&di=128&fv=17&jk=9b52dddb1f2b085e&k=res&k0=res&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=5e082b1fdbdd529b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D659967%2Ehtml&urlid=0" target="_blank" mpid="1" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">res</span></a></span>enter);} catch(Exception e){e.printStackTrace();}}setOptionalIconsVisible(menu);    return super.onMenuOpened(featureId, menu);  } else {actionBarView.showOverflowMenu();  // 把下拉菜单显示到ActionBar上return false;}}} 

以上代码首先判断首先判断sdk版本是否是android3.0之后的版本,如果是则直接反射修改menu的setOptionalIconsVisible;否则根据传入的参数featureId是否等于Window.FEATURE_ACTION_BAR来判断用户是通过点击overflow按钮还是点击物理menu键触发的,如果是通过overflow按钮触发的,则其featureId为Window.FEATURE_ACTION_BAR,但是menu=null,后面根据发射方法对menu进行赋值,并修改menu的setOptionalIconsVisible=true;如果是通过点击物理menu键触发的,则其featureId为Window.FEATURE_OPTIONS_PANEL,则调用ActionBarView的showOverflowMenu()方法,把菜单挂接到overflow下。

至此所有修改已完成,我们看一下在android2.3环境下运行效果:

技术分享


源代码下载,请点击这里




2.【ANDROID】启用 SUPPORT LIBRARY 的 ACTIONBAR


ActionBar 是自 Andoird 3.0(API level 11) 加入的新功能,目的在增进用户操作接口更丰富并统一接口外观;为了让旧版本的 Android 也能有 ActionBar,又推出 appcompat v7 提供旧 Android 版本的 API,可往前支持到 Android 2.1( Éclair, API level 7)。

如果您希望您的 app 要安装在 Android 2.1~2.3.3 的装置(也就是 7<= minSdkVersion  <= 10),且 Activity 想要有具 ActionBar 的外观,则您需要先 设定 Support Library。

本篇笔记的重点在使用 Support Library 的 ActionBar。

设定好 Support Library 后,建立一个新的 Android 项目,项目命名为 V7,刻意将 Minimum Required SDK 定在 API 8。



在项目点鼠标右键

==> Properties

==> 出现 Properties for V7 窗口

==> 点选左方的 Android

==> 卷动右方的滚动条到最下方

==> 按 Add 钮

==> 选取 android-support-v7-appcompat

修改 MainActivity 继承自 ActionBarActivity,并修改 onCreateOptionsMenu()

package com.example.v7;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.Menu;......public class MainActivity extends ActionBarActivity {    ...    ...    @Override    public boolean onCreateOptionsMenu(Menu menu)     {        getMenuInflater().inflate(R.menu.main, menu);        return super.onCreateOptionsMenu(menu);    }        ...    ...

修改 AndroidManifest.xml, 加入 android:theme ="@style/Theme.AppCompat.Light"

......<activity    android:name="com.example.v7.MainActivity"    android:label="@string/app_name"    android:theme="@style/Theme.AppCompat.Light" >    <intent-filter>        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />    </intent-filter></activity>......

除了 Theme.AppCompat.Light, Support Library 还提供了

Theme.AppCompat、  

Theme.AppCompat.Light.DarkActionBar,

一共 3 种默认的主题样式。

Google 提供了一整套的 ActionBar 图示让开发人员下载使用, http://developer.android.com/design/downloads/index.html#action-bar-icon-pack,解压后,在 /Action_Bar_Icons/holo_dark/ 和 /Action_Bar_Icons/holo_light/ 找到您要的图示复制到项目下对应位置,在本例,复制了 new、 edit、 discard、 search 等图示。

 建立 ActionBar 的菜单 — 修改默认的 /menu/main.xml

<menu    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:v7="http://schemas.android.com/apk/res-auto" >    <!-- 注意这里 -->     <!-- 新增, 要显示 -->    <item android:id="@+id/action_new"          android:icon="@drawable/ic_action_new"          android:title="@string/action_new"          v7:showAsAction="ifRoom" />    <!-- 注意这里 -->    <!-- 修改, 要显示 -->    <item android:id="@+id/action_edit"          android:icon="@drawable/ic_action_edit"          android:title="@string/action_edit"          v7:showAsAction="ifRoom" />    <!-- 注意这里 -->    <!-- 丢弃, 要显示 -->    <item android:id="@+id/action_discard"          android:icon="@drawable/ic_action_discard"          android:title="@string/action_discard"          v7:showAsAction="ifRoom" />    <!-- 注意这里 -->    <!-- 寻找, 要显示 -->    <item android:id="@+id/action_search"          android:icon="@drawable/ic_action_search"          android:title="@string/action_search"          v7:showAsAction="ifRoom" />    <!-- 注意这里 -->    <!-- Settings, 不显示, 按 "MENU" 钮才会看到 -->    <item android:id="@+id/action_settings"          android:title="@string/action_settings"          android:showAsAction="never" /></menu>

注意第 3 列

xmlns:标识符="http://schemas.android.com/apk/res-auto"

一定要加上这段文字,才能让旧版本的 Android 在 ActionBar 显现图示;其中 "标识符" 您可任意命名, 习惯上就是直接采用您app 项目名,像本例项目名为 v7。

而每个 item 的最后一列

标识符:showAsAction="ifRoom"

ifRoom 表示若 ActionBar 有足够的空间则显现本图示,若空间不够,则其余未显现的图标会出现在 MENU 菜单中。



上图在 ActionBar 只出现 2 个图示 — 新增 & 修改,其余列在菜单中。

如果硬要这个 item 的图示出现在 ActionBar,则为

标识符:showAsAction="always"

不过 Android 开发团队并不鼓励,因为各种尺寸、分辨率的 Android 装置太多,这个设定值可能导致 Activity 显示时发生无法预知的后果…

当您长按 ActionBar 的图标时,屏幕会出现该图标的说明文字


  

如果希望强制出现文字,则要再加上 withText

标识符:showAsAction="ifRoom|withText"


 gingerbread(android 2.3.3, API level 10), 3.7吋 hdpi 横向画面

仍然只出现 2 个图示( showAsAction="ifRoom"),猜想应该是 ActionBar 在 旧版本的 Android 装置只能显现 2 个图示吧…


 ICS(android 4.0.3, API level 15), 3.7吋 hdpi 横向画面

当按钮很多而 ActionBar 无法全部显示时,

meta-data android:name="android.support.UI_OPTIONS"

android:value="splitActionBarWhenNarrow"

会将 ActionBar 分割为上、下 2 部份,并在下部的 ActionBar 显示更多的按钮,不过,实验后,下部好像也只能显示 3 个按钮而已…

<activity    android:name="com.example.v7.MainActivity"    android:label="@string/app_name"    android:theme="@style/Theme.AppCompat.Light" >                <meta-data android:name="android.support.UI_OPTIONS"           android:value="splitActionBarWhenNarrow" />                ...    ...</activity>


最后就是 ActionBar 各图示的 click 事件处理,其实就是菜单的 click 事件处理

......@Overridepublic boolean onOptionsItemSelected(MenuItem item) {    // Handle presses on the action bar items    switch (item.getItemId())     {        case R.id.action_search:            openSearch();            return true;        case R.id.action_edit:            openEdit();            return true;        default:            return super.onOptionsItemSelected(item);    }} public void openSearch(){    Toast.makeText(this, "按了 寻找 钮", Toast.LENGTH_LONG).show();} public void openEdit(){    Toast.makeText(this, "按了 Edit 钮", Toast.LENGTH_LONG).show();}......

数据源 —-

http://developer.android.com/training/basics/actionbar/index.html

http://developer.android.com/guide/topics/ui/actionbar.html


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 奇云2中控台褪色怎么办 uv打印错一个字怎么办 多肉砍头后的桩怎么办 哥哥太爱我怎么办电影 吃了减肥药怀孕怎么办 win10玩不了qq堂怎么办 电脑只有c盘了怎么办 美拍直播没人看怎么办 洛神花孕妇喝了怎么办 黑枸杞泡水褐色怎么办 红薯吃多了胃胀怎么办 在赌场掉了筹码怎么办? 到缅甸被绑架了怎么办 在淘宝不给退货怎么办 鞋上魔术贴坏了怎么办 手机支架不粘了怎么办 赌博把房子输了怎么办 当发现老公有外遇时怎么办 led灯带中间不亮怎么办 飘窗的天花板凸怎么办 一受委屈就爱哭怎么办 6岁儿童叛逆期怎么办 孩子高一了厌学怎么办 除上有肥胖纹怎么办 6岁不爱写作业怎么办 初中孩子不爱写作业怎么办 孩子上课走神写作业慢怎么办 孩子作业写得慢怎么办 4岁宝宝不写作业怎么办 小孩作业写得慢怎么办 3岁宝宝不写作业怎么办 小孩不写作业怎么办呀 作业没写完的人怎么办? 孩子不写作业家长该怎么办 做作业做得慢怎么办 高一作业写得慢怎么办 孩子做作业不认真怎么办 孩子不主动做作业怎么办 写作业静不下心怎么办 小孩不写作业怎么办啊 小孩子写作业爱磨蹭怎么办