国际惯例:先发一通牢骚,他大爷的&*¥%……&,别误会我不是骂产品的,我是痛诉Android的状态栏适配的
事情是这样的,文章详情界面需要透明状态栏,下面可以评论,需求效果图如下。
头部状态栏透明:
底部有输入框:
我想关于透明状态栏的实现不算难,网上一搜有很多文章都写过,我在这里提供一些参考链接:
难点是:
先实现透明:
Window w = getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
w.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
w.setStatusBarColor(Color.TRANSPARENT);
}
但是设置android:fitsSystemWindows=”true”后效果是这样
这样的效果肯定不是我们想要的效果,后来我尝试了不使用android:fitsSystemWindows=”true”,自己监听布局变化,代码将输入框顶起到软件盘上面,下面是代码可以了解一下,但是这样写有深坑,就是华为手机还有Google原生系统有一个东西叫做NavigationBar,就是下面这个。这个东西会影响我的计算,总之自己计算就不是个明智的选择
/**
* 动态调整布局,使软件盘弹出时输入框弹出到软件盘上面
*/
private void adjustKeyboard() {
//初始化控件
rootLayout = (RelativeLayout) findViewById(R.id.root_layout);
final View v_push = findViewById(R.id.v_push);
//创建一个矩形, 用于获取输入法高度
final Rect r = new Rect();
//获取屏幕根View
final View decorView = this.getWindow().getDecorView();
//获取顶起ScrollView用的控件的布局参数, 我们是用LinearLayout包裹的所以注意来兴是LinearLayout的LayoutParams
final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v_push.getLayoutParams();
//获取布局根View的ViewTree观察器, 监听布局变化
rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
//当布局改变时, 会调用本方法
@Override
public void onGlobalLayout() {
//判断键盘显隐状态
decorView.getWindowVisibleDisplayFrame(r);
int screenHeight = rootLayout.getRootView().getHeight();
int keyboardHeight = screenHeight - r.bottom;
if (currentKeyboardHeight != keyboardHeight) {
// 当键盘状态不一致时, 再改变布局
layoutParams.height = keyboardHeight;
v_push.setLayoutParams(layoutParams);
//将键盘高度保存
currentKeyboardHeight = keyboardHeight;
}
}
});
}
后来在stackoverflow搜索到了这个坑相关的问题如:
windowSoftInputMode=“adjustResize” not working with translucent action/navbar
Android How to adjust layout in Full Screen Mode when softkeyboard is visible
我采取了其中一种方案自定义FrameLayout作为界面的根布局解决上面那一块灰白色的东东
/**
* @author Kevin
* Date Created: 3/7/14
*
* https://code.google.com/p/android/issues/detail?id=63777
*
* When using a translucent status bar on API 19+, the window will not
* resize to make room for input methods (i.e.
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are
* ignored).
*
* To work around this; override {@link #fitSystemWindows(android.graphics.Rect)},
* capture and override the system insets, and then call through to FrameLayout's
* implementation.
*
* For reasons yet unknown, modifying the bottom inset causes this workaround to
* fail. Modifying the top, left, and right insets works as expected.
*/
public final class CustomInsetsFrameLayout extends FrameLayout {
private int[] mInsets = new int[4];
public CustomInsetsFrameLayout(Context context) {
super(context);
}
public CustomInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public final int[] getInsets() {
return mInsets;
}
@Override
protected final boolean fitSystemWindows(Rect insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// Intentionally do not modify the bottom inset. For some reason,
// if the bottom inset is modified, window resizing stops working.
// TODO: Figure out why.
mInsets[0] = insets.left;
mInsets[1] = insets.top;
mInsets[2] = insets.right;
insets.left = 0;
insets.top = 0;
insets.right = 0;
}
return super.fitSystemWindows(insets);
}
@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
mInsets[0] = insets.getSystemWindowInsetLeft();
mInsets[1] = insets.getSystemWindowInsetTop();
mInsets[2] = insets.getSystemWindowInsetRight();
return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
insets.getSystemWindowInsetBottom()));
} else {
return insets;
}
}
}
你会看到,这样写确实灰白色statusbar没了,但是还是出了幺蛾子,titleBar被压在了状态栏下面,显然这也不是我们想要的效果,没有看到想要的效果先不要骂娘,你会发现我们距离成功之后一个statusBar的高度,好吧,这还不好办给他来个padding不就行了对就这么干。最终:
private void initTitleBar() {
titleBarLayout= (FrameLayout) findViewById(R.id.title_bar_layout);
int statusBarHeight = getStatusBarHeight();
Window w = getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
w.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
w.setStatusBarColor(Color.TRANSPARENT);
}else{
w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
//改变titlebar的高度
ViewGroup.LayoutParams lp = titleBarLayout.getLayoutParams();
lp.height += statusBarHeight;
titleBarLayout.setLayoutParams(lp);
//设置paddingtop
titleBarLayout.setPaddingRelative(0, statusBarHeight, 0, 0);
}
}
//获取statusbar高度
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
上面的方案只是解决方案的一种,具体问题说不定具体解决,如果你之后一个界面需要这样,你可以直接按照这种方式写,如果多个界面建议封装起来写在BaseActivitiy里面
有时候你会遇到半透明的情况效果如下:
可以加一句代码w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);在下面代码的前面
w.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
w.setStatusBarColor(Color.TRANSPARENT);