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值的內(nèi)部屬性糖声,讓view可以根據(jù)系統(tǒng)窗口(如status bar)來調(diào)整自己的布局朱巨,如果值為true,就會調(diào)整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生產(chǎn)之前)就已經(jīng)設置, 所以insets的padding值苇本,絕不會是相對于view的位置袜茧,而是相對于全屏幕。
- 任何你設置的padding都會被覆蓋瓣窄。 在同一個view上面設置了 android:fitsSystemWindows="true" 的同時笛厦,還設置了 paddingLeft paddingTop 等等,后者不會生效俺夕。
如果想讓RecycleView的內(nèi)容滾動到狀態(tài)欄之下, 可以同時設置android:fitsSystemWindows="true"和android:clipToPadding="false", 這樣在布局初始化的時候,內(nèi)容不會在狀態(tài)欄之下, 滾動的時候, 內(nèi)容可以滾到狀態(tài)欄之下;
::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 ,并且能調(diào)用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()
, 這個方法優(yōu)先于View.onApplyWindowInsets()
執(zhí)行捌议。
ViewCompat 同時也提供了 onApplyWindowInsets()
dispatchApplyWindowInsets()
,解決了兼容性的問題言缤。
fitsSystemWindows 源碼
根據(jù)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實例
系統(tǒng)的基本控件((FrameLayout, LinearLayout, 等)都使用默認的行為管挟,Support 包中有些控件使用了自定義行為。
一個使用自定義行為的示例就是側邊欄弄捕,側邊欄打開的時候僻孝,內(nèi)容是占滿整個屏幕高度的,狀態(tài)欄顯示為透明的守谓,下面是 側邊欄的內(nèi)容穿铆。
這里 DrawerLayout 使用 fitsSystemWindows 來表明需要處理 insets,但是仍然使用狀態(tài)欄的顏色來繪制狀態(tài)欄背景(狀態(tài)欄顏色為 主題的 colorPrimaryDark 所設置的顏色)斋荞。
然后 DrawerLayout 在每個子 View 上調(diào)用 dispatchApplyWindowInsets() 函數(shù)荞雏,這樣 子 View 也有 機會處理 insets,這和系統(tǒng)默認行為是不一樣的(系統(tǒng)默認行為只是吃掉這個 insets平酿,然后子 View 無法繼續(xù)處理)凤优。
CoordinatorLayout 對此也做了特殊處理,讓每個子 View 的 Behavior 可以根據(jù)系統(tǒng)窗口的大小來做不同的處理蜈彼。 還使用 fitsSystemWindows 屬性來判斷是否需要繪制狀態(tài)欄背景筑辨。
通用 CollapsingToolbarLayout 也根據(jù) fitsSystemWindows 屬性來確定何時何地繪制 內(nèi)容上方的半透明背景。
在 cheesesquare 示例項目中演示了這些 fitsSystemWindows 使用場景幸逆,可以下載該示例項目查看如何使用的棍辕。
也可以參考這個項目:
參考:
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.reibang.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