android-discuss icon indicating copy to clipboard operation
android-discuss copied to clipboard

【问答】当一个全屏Activity A进入到带有ActionBar(或ToolBar)的非全屏Activity B时,怎么解决Status Bar闪动的问题?

Open zourb opened this issue 10 years ago • 23 comments
trafficstars

如题,Activity B里Status Bar和Content会出现向下闪动的问题,这个问题怎么解决呢?

另外: http://stackoverflow.com/questions/15380257/status-bar-flicker-when-exiting-fullscreen-activity有人问过,但没有解决方案。 百度旅游 和 网易新闻 从闪屏页进入到主页可以复现这个问题。

zourb avatar Apr 20 '15 06:04 zourb

出现这个问题的原因是启动一个activity到完全显示是需要时间的,这段时间超过了人眼能感受到的界面变化的时间,所以就会出现所谓的闪屏现象。

可以考虑在AndroidManifest.xml文件中给第二个Activity设置theme时,用“android:windowBackground”属性为activity设置默认界面,这样第二个页面显示status bar时是相对于第二个activity的默认背景在变化,而不是相对于第一个activity的页面在变化,有可能解决你的问题。

zmywly8866 avatar Apr 20 '15 12:04 zmywly8866

谢谢 @zmywly8866 ,我觉得应该不是所谓的视觉效果。我的解决方案是: 全屏A改为非全屏,并把A对应的status bar颜色改成跟Acontent一致的颜色,再进入界面B会稍微好些

zourb avatar Apr 22 '15 02:04 zourb

@zourb 你这样改动不就是在改视觉效果吗?

zmywly8866 avatar Apr 22 '15 11:04 zmywly8866

@zmywly8866 是的,但是这样效果看起来还算OK,目前还没有看到更好的方案

zourb avatar Apr 24 '15 12:04 zourb

提供一个方案:http://chrisrisner.com/Switching-from-Full-Screen-to-Non-Full-Screen-Smoothly-in-Android 。我自己也在用这个方案,不过我发现有兼容性问题,在某些第三方制作的ROM上。

szuwest avatar May 25 '15 04:05 szuwest

谢谢楼上,最近找了一个不错的方案,已经用于项目中:

  1. 给Activity在清单文件里设置全屏;
  2. 在该Activity执行Finish之前,执行下面语句: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

这样在进入其他Activity就不会有Status Bar闪动的问题。

zourb avatar May 25 '15 07:05 zourb

@zourb 我试了你的方案,还是会闪动。我的情况是:非全屏A,进入全屏B,然后B finish返回A,A会闪动。

szuwest avatar May 25 '15 12:05 szuwest

有好的解决方案吗?

zhanghao813207 avatar Jul 29 '15 10:07 zhanghao813207

为啥不在切换到B的时候B的状态栏和ActionBar延时动态显示呢?

lijunhuayc avatar Jul 30 '15 01:07 lijunhuayc

状态栏延时动态显示怎么实现? @lijunhuayc

zhanghao813207 avatar Jul 30 '15 06:07 zhanghao813207

mark

mumu-3 avatar Nov 17 '15 09:11 mumu-3

@zhanghao813207 动态显示就是状态栏和actionbar通过你自己的代码来显示。 不过之前我没理解对,做成动态显示会有总B从全屏然后又变成非全屏的感觉。 楼猪有没有试试在全屏AC finish的时候先把状态栏和标题栏用代码调用显示出来后再执行finish,这样会看到先变成非全屏再切换ac,效果应该会好一些

lijunhuayc avatar Nov 17 '15 10:11 lijunhuayc

感觉上更像是每一次初始化新Activity, inflate view的时候性能上有问题..

LLin233 avatar Nov 19 '15 03:11 LLin233

mark

ityancs avatar Aug 12 '16 04:08 ityancs

@zourb Yeah,it works.

AnswerZhao avatar Sep 26 '16 03:09 AnswerZhao

@szuwest 和你遇到的情况一样,我在布局的最外面套了一层CoordinatorLayout,然后设置fitsSystemWindows属性为true,这个问题能得到解决。但是这个办法实在是有点不‘程序员’。初略看了一下CoordinatorLayout源码,在onLayout方法中有这样一段

  private void layoutChild(View child, int layoutDirection) {
        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
        final Rect parent = mTempRect1;
        parent.set(getPaddingLeft() + lp.leftMargin,
                getPaddingTop() + lp.topMargin,
                getWidth() - getPaddingRight() - lp.rightMargin,
                getHeight() - getPaddingBottom() - lp.bottomMargin);

        if (mLastInsets != null && ViewCompat.getFitsSystemWindows(this)
                && !ViewCompat.getFitsSystemWindows(child)) {
            // If we're set to handle insets but this child isn't, then it has been measured as
            // if there are no insets. We need to lay it out to match.
            parent.left += mLastInsets.getSystemWindowInsetLeft();
            parent.top += mLastInsets.getSystemWindowInsetTop();
            parent.right -= mLastInsets.getSystemWindowInsetRight();
            parent.bottom -= mLastInsets.getSystemWindowInsetBottom();
        }

        final Rect out = mTempRect2;
        GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
                child.getMeasuredHeight(), parent, out, layoutDirection);
        child.layout(out.left, out.top, out.right, out.bottom);
    }

我想这可能就是关键所在。但是可不可以将这个方法提炼出来,而不是在最外层再套一层CoordinatorLayout?

hcooll avatar Nov 18 '16 10:11 hcooll

加个解决方案,亲测可行: 在全屏activity消失之前显示状态栏,代码如下 `@Override public void onBackPressed() { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

    mUIHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            GalleryActivity.super.onBackPressed();
        }
    }, 1);
}`

fwt55 avatar Nov 25 '16 03:11 fwt55

@fwt55 你说的消失之前指的是activity生命周期的哪个阶段。

hcooll avatar Nov 25 '16 04:11 hcooll

@fwt55的方法可行,延时时间越长效果越好。。

NiaNingXue avatar Nov 30 '16 14:11 NiaNingXue

遇到同样问题

qqli007 avatar Sep 29 '17 04:09 qqli007

/**
 * 状态栏处理:解决全屏切换非全屏页面被压缩问题
 */
public void initStatusBar(int barColor) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        // 获取状态栏高度
        int statusBarHeight = getResources().getDimensionPixelSize(resourceId);
        View rectView = new View(this);
        // 绘制一个和状态栏一样高的矩形,并添加到视图中
        LinearLayout.LayoutParams params
                = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
        rectView.setLayoutParams(params);
        // 设置状态栏颜色
        rectView.setBackgroundColor(getResources().getColor(barColor));
        // 添加矩形View到布局中
        ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
        decorView.addView(rectView);
        ViewGroup rootView = (ViewGroup) ((ViewGroup) this.findViewById(android.R.id.content)).getChildAt(0);
        rootView.setFitsSystemWindows(true);
        rootView.setClipToPadding(true);
    }
}

然后在setContentView(XXX)之后调用这个方法,目前来看,我觉得是最好的解决方案。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 因为全局设置Activity转场动画,无法全局设定状态栏透明主题
    // 故在此申请占位状态栏,以解决全屏切换非全屏屏幕闪动问题
    initStatusBar(R.color.colorPrimary);
}

唯一的问题是,颜色有一点加深,我不明白是什么问题。

Cazaea avatar Mar 23 '18 08:03 Cazaea

谢谢楼上,最近找了一个不错的方案,已经用于项目中:

  1. 给Activity在清单文件里设置全屏;
  2. 在该Activity执行Finish之前,执行下面语句: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

这样在进入其他Activity就不会有Status Bar闪动的问题。

无效

snpmyn avatar Jun 13 '19 07:06 snpmyn

mark

wangwei-tt007 avatar Jul 18 '19 07:07 wangwei-tt007