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 这个类。
以下贴出原文内容:
好久没有在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>
经过这样设置以后,按理来说就应该可以了,我们在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
- Android ActionBar 兼容2.x注意细节
- Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略
- Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略
- 告别ActionBarSherlock——android.support包也能打造兼容2.x的ActionBar(1)
- actionbar 兼容包几个注意点
- Android/ActionBar兼容组件ActionBarSherlock
- ActionBar在2.X等低版本下的兼容使用
- ActionBar兼容
- Android actionBar兼容版本的使用
- Add ActionBar to Android 2.x (v7 appcompat library)
- Android 2.x版本使用ActionBar-强制显示OverflowButton
- android 2.x开发中actionbar的使用
- ActionbarActivity 向下完美兼容 ActionBar,fragment在Android2.x中
- 环信即时通讯2.x升级到3.x注意细节
- cocos2d-x-2.1.4+cygwin+eclipse android平台搭建--注意细节
- Cocos2d-x 3.8.1 移植Android平台注意的细节问题
- android 5.x设置actionBar色调
- 【Android拾遗】Android开发中的注意细节
- 第九课:编程基础(一)
- Hibernate获取Session的超实用Util工具类
- MyEclipse修改默认的jsp模板页pageEncoding为UTF-8
- 排序二叉树
- Linux常用命令--解压缩
- Android ActionBar 兼容2.x注意细节
- 什么是REST架构
- 15 多对一关联关系的检索与原理分析
- 基于Gridster的用户个性化导航栏布局
- 为啥REST如此重要?
- 从NCBI批量获取一个物种EST等相关序列
- 未来十年,互联网将如何颠覆17个传统行业
- 基于REST架构的Web Service设计
- Linux安全性和netfilter/iptables介绍