怎么让android系统中隐藏的menu按钮显示出来

来源:互联网 发布:python 和js 编辑:程序博客网 时间:2024/04/27 22:21

问题?

在将项目工程最小sdk版本和target版本提高的14之后,也就是最低支持4.0之后,menu按键在系统上显示不出来了,对于某些资深android玩家来说这点是比较坑爹的。

那么下面就是解决问题的过程了。

如需转载 注明转自http://blog.csdn.net/luoxiaozhuo/article/details/50592567

查询phonewindow的源码可以看到这样一段代码

3335        final Context context = getContext();3336        final int targetSdk = context.getApplicationInfo().targetSdkVersion;3337        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;3338        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;3339        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;3340        final boolean targetHcNeedsOptions = context.getResources().getBoolean(3341                R.bool.target_honeycomb_needs_options_menu);3342        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);33433344        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {3345            addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);3346        } else {3347            clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);3348        }

明显看出来,是需要满足某些条件这个menu按钮才会显示出来的。比如targetsdk等,当然也可以通过反射直接调用这个显示menu按键的方法来实现这个功能。这个也是网上一大堆资料告诉我们的解决办法。

try {getWindow().addFlags(WindowManager.LayoutParams.class.getField("FLAG_NEEDS_MENU_KEY").getInt(null));}catch (NoSuchFieldException e) {// Ignore since this field won't exist in most versions of Android}catch (IllegalAccessException e) {Log.w("lxz", "Could not access FLAG_NEEDS_MENU_KEY in addLegacyOverflowButton()", e);}
当然,这个解决了一大部分4.0之后的问题,但是我手机升级到 了5.1.1之后,这个方法失效了。安卓就是个坑。。。。。


然后这个时候又想到去阅读源码,只能每个版本的源码去对比,看这个之间具体发生了什么变化。

发现从5.1.0版本之后。这块的源代码变成了这样


3451        final Context context = getContext();3452        final int targetSdk = context.getApplicationInfo().targetSdkVersion;3453        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;3454        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;3455        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;3456        final boolean targetHcNeedsOptions = context.getResources().getBoolean(3457                R.bool.target_honeycomb_needs_options_menu);3458        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);34593460        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {3461            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);3462        } else {3463            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);3464        }

看这个对比一下,我了个去,谷歌这么干是有道理的。本来一个方法能干到的事情,不需要两个方法,只需要一个方法不同的两个参数就ok,也是谷歌在规范代码吧~

但是苦了我们这些码农。。。。


然后后面其实就简单了,只需要仿照那个反射来找方法来实现这个功能就ok了。

Method m = Window.class.getDeclaredMethod("setNeedsMenuKey", int.class);m.setAccessible(true);m.invoke(getWindow(), new Object[]{WindowManager.LayoutParams.class.getField("NEEDS_MENU_SET_TRUE").getInt(null)});


注意一点这里需要调用的反射是 

getDeclaredMethod();// 而不是 <span style="font-family: Arial, Helvetica, sans-serif;">getMethod();</span>

getMethod();
Returns a <code>Method</code> object which represents the public method with the specified name and parameter types. <code>(Class[]) null</code> is equivalent to the empty array. This method first searches the class C represented by this <code>Class</code>, then the superclasses of C and finally the interfaces implemented by C and finally the superclasses of C for a method with matching name.
<pre code_snippet_id="1566952" snippet_file_name="blog_20160127_2_9556582" name="code" class="java">getDeclaredMethod()
Returns a <code>Method</code> object which represents the method matching the specified name and parameter types that is declared by the class represented by this <code>Class</code>.

当然完整代码可能就需要加上一个版本判断来做不同的处理了。

通过这个Build.VERSION.SDK_INT来判断是否满足条件,去反射不同的方法来实现。

Build.VERSION.SDK_INT 21 android 5.0.1

Build.VERSION.SDK_INT 22 android 5.1.1

这觉B是坑爹。。。。

我只能再通过下载下来的源码再跟进去查一次了

发现这个是从sdk 22开始才有的特性

故此具体代码就变成了

if (Build.VERSION.SDK_INT < 22) {getWindow().addFlags(WindowManager.LayoutParams.class.getField("FLAG_NEEDS_MENU_KEY").getInt(null));} else {Method m = Window.class.getDeclaredMethod("setNeedsMenuKey",int.class);m.setAccessible(true);m.invoke(getWindow(),new Object[] { WindowManager.LayoutParams.class.getField("NEEDS_MENU_SET_TRUE").getInt(null) });}

具体的try catch 直接用ide处理下就ok了。



0 0
原创粉丝点击