fitsSystemWindows理解

fitsSystemWindows 的定义

Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

这个一个boolean值的内部属性,让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间。只有在非嵌入式的activity的view才有效果。

fitsSystemWindows 的作用

android:fitsSystemWindows="true" attribute gives you: it sets the padding of the View to ensure the contents don’t overlay the system windows.

设置View的padding,确定content不会与system windows重叠。

A few things to keep in mind:

  • fitsSystemWindows is applied depth first * — ordering matters: it’s the first View that consumes the insets that makes a difference
    Insets are always relative to the full window — insets may be applied even before layout happens, so don’t assume the default behavior knows anything about the position of a View when applying its padding
    Any other padding you’ve set is overwritten — you’ll note that paddingLeft /paddingTop /etc is ineffective if you are using android:fitsSystemWindows="true" on the same View

有几点是需要注意的:

  • 属性需要在root view设置,只有root view消费insets才会生效。
  • insets 是相对于全屏幕的。insets(边框)可能在 layout 之前(view生产之前)就已经设置, 所以insets的padding值,绝不会是相对于view的位置,而是相对于全屏幕。
  • 任何你设置的padding都会被覆盖。 在同一个view上面设置了 android:fitsSystemWindows="true" 的同时,还设置了 paddingLeft paddingTop 等等,后者不会生效。

如果想让RecycleView的内容滚动到状态栏之下, 可以同时设置android:fitsSystemWindows="true"和android:clipToPadding="false", 这样在布局初始化的时候,内容不会在状态栏之下, 滚动的时候, 内容可以滚到状态栏之下;
::android:clipToPadding="false"的作用是是让padding的位置也可以用来绘制, clipToPadding默认是true::

自定义fitsSystemWindows

On KitKat and below, your custom View could override fitSystemWindows()
and provide any functionality you wanted — just return true
if you’ve consumed the insets or false if you’d like to give other Views a chance.

在KitKat(4.4)或者4.4以下的版本,在自定义view中重写fitSystemWindows()方法,如果要消费insets则返回true , 返回false则让其他view去消费。

on Lollipop and higher devices, we provide some new APIs to make customizing this behavior much easier and consistent with other behaviors for Views. You’ll instead override onApplyWindowInsets(), which allows the View to consume as much or as little of the insets as you need and be able to call dispatchApplyWindowInsets() on child views as needed.

Lollipop(5.0) 或者 5.0以上版本, 提供了新的API ,只要重写onApplyWindowInsets(),就能允许自定义view去消费任何大小的insets ,并且能调用dispatchApplyWindowInsets() 让子view接着消费insets。

you don’t even need to subclass your Views if you only need custom behavior on Lollipop and higher you can use ViewCompat.setOnApplyWindowInsetsListener(), which will be given preference over the View’s onApplyWindowInsets(). ViewCompat also provides helper methods for calling onApplyWindowInsets() and dispatchApplyWindowInsets() without version checking.

在Lollipop(5.0)或者5.0以上的版本,如果不想继承view的话,可以使用ViewCompat.setOnApplyWindowInsetsListener() , 这个方法优先于View.onApplyWindowInsets()执行。
ViewCompat 同时也提供了 onApplyWindowInsets() dispatchApplyWindowInsets() ,解决了兼容性的问题。

fitsSystemWindows 源码

根据FITS_SYSTEM_WINDOWS标志位,无论哪个版本,默认都是直接设置padding

protected boolean fitSystemWindows(Rect insets) {
        if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
            if (insets == null) {
                // Null insets by definition have already been consumed.
                // This call cannot apply insets since there are none to apply,
                // so return false.
                return false;
            }
            // If we're not in the process of dispatching the newer apply insets call,
            // that means we're not in the compatibility path. Dispatch into the newer
            // apply insets path and take things from there.
            try {
                mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
                return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
            } finally {
                mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
            }
        } else {
            // We're being called from the newer apply insets path.
            // Perform the standard fallback behavior.
            return fitSystemWindowsInt(insets);
        }
    }

    private boolean fitSystemWindowsInt(Rect insets) {
        if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
            mUserPaddingStart = UNDEFINED_PADDING;
            mUserPaddingEnd = UNDEFINED_PADDING;
            Rect localInsets = sThreadLocal.get();
            if (localInsets == null) {
                localInsets = new Rect();
                sThreadLocal.set(localInsets);
            }
            boolean res = computeFitSystemWindows(insets, localInsets);
            mUserPaddingLeftInitial = localInsets.left;
            mUserPaddingRightInitial = localInsets.right;
            internalSetPadding(localInsets.left, localInsets.top,
                    localInsets.right, localInsets.bottom);
            return res;
        }
        return false;
    }
  public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
            // We weren't called from within a direct call to fitSystemWindows,
            // call into it as a fallback in case we're in a class that overrides it
            // and has logic to perform.
            if (fitSystemWindows(insets.getSystemWindowInsets())) {
                return insets.consumeSystemWindowInsets();
            }
        } else {
            // We were called from within a direct call to fitSystemWindows.
            if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
                return insets.consumeSystemWindowInsets();
            }
        }
        return insets;
    }

fitsSystemWindows实例

系统的基本控件((FrameLayout, LinearLayout, 等)都使用默认的行为,Support 包中有些控件使用了自定义行为。
一个使用自定义行为的示例就是侧边栏,侧边栏打开的时候,内容是占满整个屏幕高度的,状态栏显示为透明的,下面是 侧边栏的内容。


这里 DrawerLayout 使用 fitsSystemWindows 来表明需要处理 insets,但是仍然使用状态栏的颜色来绘制状态栏背景(状态栏颜色为 主题的 colorPrimaryDark 所设置的颜色)。
然后 DrawerLayout 在每个子 View 上调用 dispatchApplyWindowInsets() 函数,这样 子 View 也有 机会处理 insets,这和系统默认行为是不一样的(系统默认行为只是吃掉这个 insets,然后子 View 无法继续处理)。
CoordinatorLayout 对此也做了特殊处理,让每个子 View 的 Behavior 可以根据系统窗口的大小来做不同的处理。 还使用 fitsSystemWindows 属性来判断是否需要绘制状态栏背景。
通用 CollapsingToolbarLayout 也根据 fitsSystemWindows 属性来确定何时何地绘制 内容上方的半透明背景。
cheesesquare 示例项目中演示了这些 fitsSystemWindows 使用场景,可以下载该示例项目查看如何使用的。

也可以参考这个项目:

https://github.com/Jude95/FitSystemWindowLayout

参考:
https://stackoverflow.com/questions/3355367/height-of-statusbar
http://blog.chengyunfeng.com/?p=905
https://stackoverflow.com/questions/28387289/fitsystemwindows-programmatically-for-status-bar-transparency
http://www.jianshu.com/p/f3683e27fd94
https://developer.android.com/reference/android/support/design/widget/AppBarLayout.html
https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec?linkId=19685562
https://github.com/hehonghui/android-tech-frontier/blob/master/issue-35/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E8%A6%81%E7%94%A8fitsSystemWindows.md

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,577评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,088评论 2 44
  • 需要引用到的头文件有 相册权限 照相机权限 麦克风权限 通知权限 定位权限 通讯录权限
    SincereDu阅读 407评论 0 0
  • 早上一起床,儿子就出去了。直到午饭时间给他打电话,接近12点才回来。吃饭时,儿子:妈妈,我给你说过几次我要上班的事...
    小瓶盖Q日记阅读 309评论 1 1
  • 在2017.5.14macaca发布了 XCTestWD 、UIAutomatorWD,接下来就是面临各种的升级问...
    _夏兮阅读 1,028评论 0 2