谈谈“adjustResize”在沉浸式状态栏下的失效问题

前言

关于“沉浸式”的介绍,请看另外一篇文章:刨根问底-论Android“沉浸式”,文章中详细介绍了“沉浸式”的相关知识,最后给出了Android 4.4 及以上“状态栏着色”的适配方案。

这里简单介绍下,一共分为两步:

  1. 在主题中增加以下属性,这会使得“状态栏”透明。
    values-v19/styles.xml:
    <item name="android:windowTranslucentStatus">true</item>

  2. 上一步会使得 Activity 的布局“陷入”到状态栏中,所以需要配合另外一个属性:fitSystemWindows

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:fitsSystemWindows="true"/>
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true" />
        </RelativeLayout>
    </LinearLayout>
    

注意:这里将 fitSystemWindows 设置到了需要加上 paddingTop 的 View(不太明白?那就先看下刨根问底-论Android“沉浸式”),而不是 xml 布局的根元素!!!

这里解释下,为何不建议将 fitSystemWindows 设置到 xml 布局的根元素,基于几下几个可能出现的问题:

  • 必须将背景色设置到 xml 布局的根元素,而不是在标题栏设置。
    为何这么说呢?如果不设置根元素的背景色,你会看到状态栏的颜色和根布局的背景一致,而不是和我们的标题栏一致(终极原因是因为根布局被系统加上 paddingTop 了。。。)。
  • 如果背景色设置到了根元素,那么布局内容的颜色(图中的白色,或其他颜色)还需要再设置一遍(这也是必须的),不然整个布局都是蓝色的,这个肯定不行。
  • 其他,还没想到~

效果图如下:

正题

点击输入框(Activity 的键盘模式设置为 adjustResize),你会发现 ToolBar 被拉伸了。

网上有些文章说到 ToolBar 文字被顶上去,但是高度没有变化。区别在于:他们设置了 ToolBar 的具体高度,而不是使用的 wrap_content 属性。一般做法都是通过反射拿到状态栏的高度,再加上一个标题栏的高度作为 ToolBar 的实际高度。个人觉得这并不是一种好的做法,毕竟反射获取状态栏高度不是一个“合法渠道”。

这里需要解释下,为何会出现“拉伸”的情况?

我们都知道 adjustResize 模式,会使用界面“压缩”来腾出底部空间,显示键盘。

如果你的 View 使用了 android:fitsSystemWindows="true",并且它的高度是 wrap_content 的。那么,当键盘出现的时候,系统会设置一个 padingBottom 值到此 View,它的数值正好等于键盘的高度。

因为 ToolBar 设置了 android:fitsSystemWindows="true" 且高度是 wrap_content,所以导致 ToolBar 被系统加上了 paddingBottom

此时,我想到的第一个思路就是能不能不让系统去设置这个 paddingBottom,这样不就解决了“拉伸”的问题?

解决思路:
View#onMeasure() 方法最后,强制设置 paddingBottom = 0

为了不入侵 ToolBar,另外也不是所有项目都是用了 ToolBar,很多项目都有自己的“TitleBar”,所以我们将上面的 xml 布局改造如下:

...    
<com.example.hiphonezhu.immersivedemo.ImmerseGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:fitsSystemWindows="true">
    <!-- 可以是其他 TitleBar -->
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</com.example.hiphonezhu.immersivedemo.ImmerseGroup>
...

用一个 ImmerseGroup 去包裹 ToolBar,将android:backgroundandroid:fitsSystemWindows两个属性从 ToolBar 移到 ImmerseGroup。

ImmerseGroup 的实现也很简单:

public class ImmerseGroup extends FrameLayout {
    public ImmerseGroup(Context context) {
        super(context);
    }

    public ImmerseGroup(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ImmerseGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), 0);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

重点就是重写 onMeasure() 方法,设置 paddingBottom = 0

重新运行,点击输入框,ToolBar 没有再被“拉伸”了。

但是,又出现了另外一个问题:输入框不见了,其实是输入框没有被顶起来。

这个问题就是网上很多文章描述的 adjustResize 失效问题,解决方案基本都一致:在跟布局加上 android:fitsSystemWindows="true"。这个方案前面已经讨论过,不是一个好的方案。

问题参考:http://blog.163.com/ittfxin@126/blog/static/11067486320162210549679/


我们最终的解决方案是:通过监听android.R.id.content 布局的变化,动态去改变它的高度,来为键盘腾出空间。

这里可以直接使用了一个工具类:AndroidBug5497Workaround

public class AndroidBug5497Workaround {
    public static void assistActivity(View content) {
        new AndroidBug5497Workaround(content);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private ViewGroup.LayoutParams frameLayoutParams;

    private AndroidBug5497Workaround(View content) {
       if (content != null) {
          mChildOfContent = content;
          mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
               public void onGlobalLayout() {
                   possiblyResizeChildOfContent();
                    }
         });
         frameLayoutParams = mChildOfContent.getLayoutParams();
       }
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            //如果两次高度不一致
            //将计算的可视高度设置成视图的高度
            frameLayoutParams.height = usableHeightNow;
            mChildOfContent.requestLayout();//请求重新布局
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        //计算视图可视高度
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom);
    }
}

在需要适配的 Activity 调用如下方法:

AndroidBug5497Workaround.assistActivity(findViewById(android.R.id.content));

最后的效果如下:

示例代码参考:ImmersiveDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容