1. 程式人生 > >設定頁彈框背景不透明問題分析及解決

設定頁彈框背景不透明問題分析及解決

一、問題背景

在開發新版本時,有個需求是使用者通過點選跳轉到系統設定介面時,彈出一個對話方塊。對話方塊用來描述為什麼需要使用者進行設定,引導使用者完成開啟設定。在自己的activity中彈出對話方塊大家都知道怎麼做,

但是在系統設定介面彈出對話方塊肯定沒那麼方便了。一開始有兩個方向:

  1. 在開啟設定頁同時開啟一個dialog樣式的activity,這樣給人的感覺就像是真正的對話方塊。
  2. 使用懸浮窗,將dialog view 通過windowsManager add到window中。
這兩種方式都能達成需求,但是第二種懸浮窗的方式控制不便,還需要特殊許可權。所以最終選用的是第一種。 二、遇到的問題 在使用第一種方式時發現在某些機型上會出現彈出的dialog樣式的activity背景是全黑的,並不是我們設定的style。
我們寫個簡單的demo來驗證一下: 我們在MainActivity 中先啟動設定介面,再啟動DialogActivity,程式碼如下: @Override   protected void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_a);   Button btn = (Button) findViewById(R.id.main_btn);   btn.setOnClickListener(new View.OnClickListener() {
  @Override   public void onClick(View v) {   launchSettingActivity();   launchActivity(MainActivity.this, DialogActivity.class);   }   });   } 這裡我們的DialogActivity的style是設定為dialog樣式的:   <activity   android:name=".lifecircl.DialogActivity"   android:theme="@style/Dialog.Translucent">   </activity> style:
  <style name="Dialog.Translucent" parent="Theme.AppCompat.Dialog">   <item name="android:windowFrame">@android:color/transparent</item>   <item name="android:windowIsFloating">true</item>   <item name="android:windowIsTranslucent">true</item>   <item name="android:windowNoTitle">true</item>   <item name="android:windowBackground">@android:color/transparent</item>   <item name="android:backgroundDimAmount">0.3</item>   </style> 我們希望看到的是如下圖彈框在設定介面顯示:

發現確實也沒有問題,設定activity與DialogActivity分別按順序入棧顯示。可是發現在部分機型上會出現下圖這種問題:

背景不再是我們想要的透明而是全黑的背景。。。這就坑爹了。 三、問題分析 問題猜想:是不是因為設定頁介面還未繪製顯示出來,而透明背景的DialogActivity背景就是預設黑色背景呢? 為了驗證我們的猜想,我們先啟動設定頁延遲啟動彈框Activity;我們看下效果怎麼樣:   @Override   protected void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_a);   Button btn = (Button) findViewById(R.id.main_btn);   btn.setOnClickListener(new View.OnClickListener() {   @Override   public void onClick(View v) {       launchSettingActivity();       delayLaunchActivity();   }   });   } private void delayLaunchActivity() {   mHandler.postDelayed(new Runnable() {   @Override   public void run() {   launchActivity(A_Activity.this, DialogActivity.class);   }   }, 200);   } 我們通過handler延遲200ms啟動DialogActivity,發現這樣我們的DialogActivity顯示正常,是我們想要的方式。 為了發現其中的問題,我們先用一個普通的B_Activity模擬設定頁。 我們來看看不延遲200ms生命週期的回撥: MainActivity onPause:  B_Activity onCreate:  B_Activity onResume:  B_Activity onPause:  DialogActivity onCreate:  DialogActivity onResume:  MainActivity onStop: 接下來看看延遲200ms啟動DialogActivity時的生命週期回撥: MainActivity onPause: B_Activity onCreate: B_Activity onResume: B_Activity onPause: DialogActivity onCreate: DialogActivity onResume: MainActivity onStop: 觀察發現無論是否延遲200ms,生命週期回撥是一致的(具體生命週期與啟動延遲時長有關)。我想真正的原因與Activity啟動機制有關,因為未深入,以後有機會再補充。 為了避免在設定頁介面還未繪製完就彈出對話方塊,我們是不是可以在設定介面完全展示後再彈出對話方塊呢? 我們知道在MainActivity啟動B_Activity完成時會回撥MainActivity的onStop,這時MainActivity肯定是不可見的。為了達成我們的需求是不是可以在MainActivity onStop中啟動DialogActivity呢?   @Override   protected void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_a);   Button btn = (Button) findViewById(R.id.main_btn);   btn.setOnClickListener(new View.OnClickListener() {   @Override   public void onClick(View v) {           launchSettingActivity();           isClick = true;        }   });   }    @Override   protected void onStop() {   super.onStop();         if (isClick) {                  launchActivity(A_Activity.this, DialogActivity.class);                  isClick = false;              }   } 這時的效果與延遲是一致的,也不會出現背景不透明的現象。模擬的生命週期如下: MainActivity onPause:  B_Activity onCreate:  B_Activity onResume:  MainActivity onStop:  B_Activity onPause:  DialogActivity onCreate:  DialogActivity onResume: 三、解決方案 根據以上所知為了避免在彈出對話方塊背景不透明問題,我們可以使用兩種方法:
  1. 延遲啟動對話方塊Activity
  2. 在生命週期回撥函式onStop()中啟動對話方塊Activity
因為延遲啟動的延遲時長多少不好設定,長了會造成體驗不好,短了會出現黑屏”一閃而過“的問題,所有推薦使用第二種方法。 四、問題總結 雖然問題解決了,但是延遲啟動生效的原因還有待更加深入。以後有機會再做探索補充,也希望知道原因的同學能為我解惑。