1. 程式人生 > >Android沉浸式與SearchView的坑

Android沉浸式與SearchView的坑

Android開發雖然不算多難,但其中確實包含了這樣那樣的坑,我今天要說的這個坑可能很少人會遇到,不過萬一呢。。。

一開始是我想在專案的toolbar上新增谷歌原生支援的搜尋功能,但是怎麼弄都不對,鍵盤彈出以後搜尋框會自動消失,如下圖所示,可能比較亂,將就看看吧:

鍵盤彈出後搜尋框會自動消失

經過兩天的不斷修改嘗試,終於找到了癥結所在:

在styles.xml檔案中設定windowTranslucentStatus=true會導致SearchView顯示不正確!

同時還得到一個結論:

targetSdkVersion對最終編譯結果有較大的影響!

先說targetSdkVersion對最終編譯結果的影響,這些影響主要在support庫的介面上。比如同樣使用Theme.AppCompat.Light.NoActionBar,targetSdkVersion<21編譯的結果執行在api21以上的手機上,就不自帶沉浸式狀態列。而targetSdkVersion>=21編譯的就自帶沉浸式狀態列,不過api19的還是需要使用windowTranslucentStatus來開啟沉浸式狀態列的。

再比如跟上例一樣的targetSdkVersion設定,用同樣的NotificationCompat生成的通知的顯示效果是不一樣的,如下圖:

targetSdkVersion<21編譯的結果

targetSdkVersion>=21編譯的結果

甚至還有更可怕的,是會影響到一些奇怪的地方,比如友盟的反饋元件介面:

targetSdkVersion=15編譯的結果
targetSdkVersion>=19編譯的結果

我知道一般人是看不出差別來的,那麼看下面這個圖:
仔細看看差別

這下看得出來了吧,完全影響到介面佈局了,而且語音按鈕的點選功能也失效了!!!

所以為了保證友盟的反饋元件的可用性,我只能現在targetSdkVersion=15了。

具體的原因還不太清楚,可能是我自己本身哪裡使用得不太對吧。。。

再說回到windowTranslucentStatus。

為什麼要設定windowTranslucentStatus呢?windowTranslucentStatus顧名思義是透明狀態列的意思,參照前面所說的,如果targetSdkVersion<21,如果要實現沉浸式的效果,就需要設定windowTranslucentStatus,或者如果想要api19也實現沉浸式效果,無論targetSdkVersion為多少都要設定windowTranslucentStatus。

具體如何實現沉浸式狀態列,可以參考這篇。

那是不是沉浸式狀態列和SearchView就不能同時使用了呢?當然不是:

  1. 如果你的targetSdkVersion>=21,那麼只要不給api19設定沉浸式效果就可以了,api21以上的版本會自動開啟沉浸式效果,SearchView工作也正常。
  2. 如果你的targetSdkVersion<21,或者你想給api19也設定沉浸式效果,那麼就將styles.xml裡面的windowTranslucentStatus刪掉,然後使用程式碼的方式來實現沉浸式吧。

下面是簡單的沉浸式程式碼實現:

public class StatusBarCompat
{
public static void setupStatusBarView(Activity activity, ViewGroup decorViewGroup, boolean on,int colorRes) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { setTranslucentStatus(activity, on); View mStatusBarTintView = new View(activity); int mStatusBarHeight = 0; int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { mStatusBarHeight = activity.getResources().getDimensionPixelSize(resourceId); } FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, mStatusBarHeight); params.gravity = Gravity.TOP; mStatusBarTintView.setLayoutParams(params); mStatusBarTintView.setBackgroundResource(colorRes); mStatusBarTintView.setVisibility(View.VISIBLE); decorViewGroup.addView(mStatusBarTintView); } } private static void setTranslucentStatus(Activity activity,boolean on) { Window win = activity.getWindow(); WindowManager.LayoutParams winParams = win.getAttributes(); final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; if (on) { winParams.flags |= bits; } else { winParams.flags &= ~bits; } win.setAttributes(winParams); } }

其實這個WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS的作用和windowTranslucentStatus是一樣的,但是為什麼通過程式碼的方式和通過資原始檔的方式來實現有這麼大的差別就不清楚了。