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

10 篇文章 0 订阅

问题?

在将项目工程最小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);
3343
3344        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);
3459
3460        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了。



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值