当透明状态栏遇到输入框
前言
国际惯例:先发一通牢骚,他大爷的&*¥%……&,别误会我不是骂产品的,我是痛诉Android的状态栏适配的
事情是这样的,文章详情界面需要透明状态栏,下面可以评论,需求效果图如下。
头部状态栏透明:
底部有输入框:
我想关于透明状态栏的实现不算难,网上一搜有很多文章都写过,我在这里提供一些参考链接:
- Android开发:Translucent System Bar 的最佳实践
- 透明状态栏(StatusBar)的全适配
- Android状态栏合集-管你透不透明
- Android-transulcent-status-bar
- Android 透明状态栏实现方案
难点是:
- 如果布局中要用到软键盘,就必须加上android:fitsSystemWindows=”true”属性,否则键盘弹出时,adjustResize属性不起作用,这样就会导致软件盘覆盖输入框。但是当你加上android:fitsSystemWindows=”true”时会导致状态栏变成灰白色
- 华为手机,准确的说是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);
参考链接
- http://stackoverflow.com/questions/21092888/windowsoftinputmode-adjustresize-not-working-with-translucent-action-navbar
更多相关文章
- 模仿iOS版微信的滑动View效果
- Android实现加载富文本以及SpannableString、SpannableStringBui
- Android(安卓)View的测量、布局、绘制过程详解(上)
- android 定制 View派生类
- Android中实现程序前后台切换效果。
- android 你或许不知道的屏幕适配
- Android(安卓)Layout 之 RelativeLayout RelativeLayout.LayoutP
- 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用
- 关于android UI布局自适应