设置页弹框背景不透明问题分析及解决

来源:互联网 发布:microsoft画图软件 编辑:程序博客网 时间:2024/05/28 05:17

一、问题背景

在开发新版本时,有个需求是用户通过点击跳转到系统设置界面时,弹出一个对话框。对话框用来描述为什么需要用户进行设置,引导用户完成开启设置。在自己的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

因为延迟启动的延迟时长多少不好设定,长了会造成体验不好,短了会出现黑屏”一闪而过“的问题,所有推荐使用第二种方法。

四、问题总结

虽然问题解决了,但是延迟启动生效的原因还有待更加深入。以后有机会再做探索补充,也希望知道原因的同学能为我解惑。
0 0
原创粉丝点击