android-discuss
android-discuss copied to clipboard
【问答】当一个全屏Activity A进入到带有ActionBar(或ToolBar)的非全屏Activity B时,怎么解决Status Bar闪动的问题?
如题,Activity B里Status Bar和Content会出现向下闪动的问题,这个问题怎么解决呢?
另外: http://stackoverflow.com/questions/15380257/status-bar-flicker-when-exiting-fullscreen-activity有人问过,但没有解决方案。 百度旅游 和 网易新闻 从闪屏页进入到主页可以复现这个问题。
出现这个问题的原因是启动一个activity到完全显示是需要时间的,这段时间超过了人眼能感受到的界面变化的时间,所以就会出现所谓的闪屏现象。
可以考虑在AndroidManifest.xml文件中给第二个Activity设置theme时,用“android:windowBackground”属性为activity设置默认界面,这样第二个页面显示status bar时是相对于第二个activity的默认背景在变化,而不是相对于第一个activity的页面在变化,有可能解决你的问题。
谢谢 @zmywly8866 ,我觉得应该不是所谓的视觉效果。我的解决方案是: 全屏A改为非全屏,并把A对应的status bar颜色改成跟Acontent一致的颜色,再进入界面B会稍微好些
@zourb 你这样改动不就是在改视觉效果吗?
@zmywly8866 是的,但是这样效果看起来还算OK,目前还没有看到更好的方案
提供一个方案:http://chrisrisner.com/Switching-from-Full-Screen-to-Non-Full-Screen-Smoothly-in-Android 。我自己也在用这个方案,不过我发现有兼容性问题,在某些第三方制作的ROM上。
谢谢楼上,最近找了一个不错的方案,已经用于项目中:
- 给Activity在清单文件里设置全屏;
- 在该Activity执行Finish之前,执行下面语句: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
这样在进入其他Activity就不会有Status Bar闪动的问题。
@zourb 我试了你的方案,还是会闪动。我的情况是:非全屏A,进入全屏B,然后B finish返回A,A会闪动。
有好的解决方案吗?
为啥不在切换到B的时候B的状态栏和ActionBar延时动态显示呢?
状态栏延时动态显示怎么实现? @lijunhuayc
mark
@zhanghao813207 动态显示就是状态栏和actionbar通过你自己的代码来显示。 不过之前我没理解对,做成动态显示会有总B从全屏然后又变成非全屏的感觉。 楼猪有没有试试在全屏AC finish的时候先把状态栏和标题栏用代码调用显示出来后再执行finish,这样会看到先变成非全屏再切换ac,效果应该会好一些
感觉上更像是每一次初始化新Activity, inflate view的时候性能上有问题..
mark
@zourb Yeah,it works.
@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?
加个解决方案,亲测可行: 在全屏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 你说的消失之前指的是activity生命周期的哪个阶段。
@fwt55的方法可行,延时时间越长效果越好。。
遇到同样问题
/**
* 状态栏处理:解决全屏切换非全屏页面被压缩问题
*/
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);
}
唯一的问题是,颜色有一点加深,我不明白是什么问题。
谢谢楼上,最近找了一个不错的方案,已经用于项目中:
- 给Activity在清单文件里设置全屏;
- 在该Activity执行Finish之前,执行下面语句: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
这样在进入其他Activity就不会有Status Bar闪动的问题。
无效
mark