1. 程式人生 > >怎麼讓android系統中隱藏的menu按鈕顯示出來

怎麼讓android系統中隱藏的menu按鈕顯示出來

問題?

在將專案工程最小sdk版本和target版本提高的14之後,也就是最低支援4.0之後,menu按鍵在系統上顯示不出來了,對於某些資深android玩家來說這點是比較坑爹的。

那麼下面就是解決問題的過程了。

如需轉載 註明轉自http://blog.csdn.net/luoxiaozhuo/article/details/50592567

查詢phonewindow的原始碼可以看到這樣一段程式碼


明顯看出來,是需要滿足某些條件這個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版本之後。這塊的原始碼變成了這樣


看這個對比一下,我了個去,谷歌這麼幹是有道理的。本來一個方法能幹到的事情,不需要兩個方法,只需要一個方法不同的兩個引數就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了。