設定頁彈框背景不透明問題分析及解決
阿新 • • 發佈:2019-01-23
一、問題背景
我們寫個簡單的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: 三、解決方案 根據以上所知為了避免在彈出對話方塊背景不透明問題,我們可以使用兩種方法:
在開發新版本時,有個需求是使用者通過點選跳轉到系統設定介面時,彈出一個對話方塊。對話方塊用來描述為什麼需要使用者進行設定,引導使用者完成開啟設定。在自己的activity中彈出對話方塊大家都知道怎麼做,
但是在系統設定介面彈出對話方塊肯定沒那麼方便了。一開始有兩個方向:
- 在開啟設定頁同時開啟一個dialog樣式的activity,這樣給人的感覺就像是真正的對話方塊。
- 使用懸浮窗,將dialog view 通過windowsManager add到window中。
發現確實也沒有問題,設定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: 三、解決方案 根據以上所知為了避免在彈出對話方塊背景不透明問題,我們可以使用兩種方法:
- 延遲啟動對話方塊Activity
- 在生命週期回撥函式onStop()中啟動對話方塊Activity