日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

android /system,android:fitSystemWindows详解

發布時間:2025/3/15 windows 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android /system,android:fitSystemWindows详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從Android 4.4開始,Android系統加入了一個比較酷的功能,就是我們可以設置狀態欄的的顏色了,有個這個功能,狀態欄就不再是黑乎乎的了,我們就可以根據我們應用的主色去設置狀態欄的顏色,使得應用體驗變得好一些,所以我們通過如下方式設置狀態欄透明。

window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,?WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);?window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,?WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

但是設置了狀態欄和導航欄透明之后,發現Activity的contentView超出了ActionBar,那么我們就要使用fitSystemWindws來解決這個問題,關于具體如何解決這個問題,在Android4.4新的特性,在應用內開啟透明狀態欄和透明虛擬按鈕這篇博客中有詳細介紹。

那么android:fitSystemWindows到底是什么東西啊,它是怎樣計算的?

在Android Framework的源代碼中查看View.java,有這幾個重要方法,如下:

dispatchApplyWindowInsets

onApplyWindowInsets

fitSystemWindows

是一個自定義的View,并且覆蓋View的這三個方法,打印出Log,可以發現這三個方法的調用順序是

dispatchApplyWindowInsets

onApplyWindowInsets

fitSystemWindows

這里我們通過代碼調試的方法來查看Android Framework的方法調用堆棧,如圖:

根據堆棧可以發現,dispatchApplyWindowInsets方法是在ViewRootImpl.performMeasure(int,int)方法中調用的。也就是說,dispatchApplyWindowInsets是在整個View Hierarchy的measure過程中調用的。

在從layout文件中解釋到fitSystemWindows為true設置標志位。那這個標志為在什么時候起的作用。

case?com.android.internal.R.styleable.View_fitsSystemWindows:

if?(a.getBoolean(attr,?false))?{

viewFlagValues?|=?FITS_SYSTEM_WINDOWS;viewFlagMasks?|=?FITS_SYSTEM_WINDOWS;}break;

再看上面那幅堆棧圖,在ActionBarOverlayLayout.measure()中開始調用fitSystemWindows的相關方法,進入ActionBarOverlayLayout的源碼。

protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{//通過findViewById方法,得到布局文件中的viewpullChildren();int?maxHeight?=?0;int?maxWidth?=?0;int?childState?=?0;int?topInset?=?0;int?bottomInset?=?0;//測量ActionBar的高度和寬度measureChildWithMargins(mActionBarTop,?widthMeasureSpec,?0,?heightMeasureSpec,?0);

LayoutParams?lp?=?(LayoutParams)?mActionBarTop.getLayoutParams();

maxWidth?=?Math.max(maxWidth,

mActionBarTop.getMeasuredWidth()?+?lp.leftMargin?+?lp.rightMargin);

maxHeight?=?Math.max(maxHeight,

mActionBarTop.getMeasuredHeight()?+?lp.topMargin?+?lp.bottomMargin);

childState?=?ViewUtils.combineMeasuredStates(childState,

ViewCompat.getMeasuredState(mActionBarTop));//?xlarge?screen?layout?doesn't?have?bottom?action?bar.//測量ActionBar底部區域的高度和寬度if?(mActionBarBottom?!=?null)?{

measureChildWithMargins(mActionBarBottom,?widthMeasureSpec,?0,?heightMeasureSpec,?0);

lp?=?(LayoutParams)?mActionBarBottom.getLayoutParams();

maxWidth?=?Math.max(maxWidth,

mActionBarBottom.getMeasuredWidth()?+?lp.leftMargin?+?lp.rightMargin);

maxHeight?=?Math.max(maxHeight,

mActionBarBottom.getMeasuredHeight()?+?lp.topMargin?+?lp.bottomMargin);

childState?=?ViewUtils.combineMeasuredStates(childState,

ViewCompat.getMeasuredState(mActionBarBottom));

}final?int?vis?=?ViewCompat.getWindowSystemUiVisibility(this);final?boolean?stable?=?(vis?&?SYSTEM_UI_FLAG_LAYOUT_STABLE)?!=?0;if?(stable)?{//?This?is?the?standard?space?needed?for?the?action?bar.?For?stable?measurement,//?we?can't?depend?on?the?size?currently?reported?by?it?--?this?must?remain?constant.topInset?=?mActionBarHeight;//考慮到ActionbarTab的高度,計算topInsetif?(mHasNonEmbeddedTabs)?{final?View?tabs?=?mActionBarTop.getTabContainer();if?(tabs?!=?null)?{//?If?tabs?are?not?embedded,?increase?space?on?top?to?account?for?them.topInset?+=?mActionBarHeight;

}

}

}?else?if?(mActionBarTop.getVisibility()?!=?GONE)?{//?This?is?the?space?needed?on?top?of?the?window?for?all?of?the?action?bar//?and?tabs.topInset?=?mActionBarTop.getMeasuredHeight();

}//如果ActionBar是split模式,考慮底部的高度,計算insetBottomif?(mDecorToolbar.isSplit())?{//?If?action?bar?is?split,?adjust?bottom?insets?for?it.if?(mActionBarBottom?!=?null)?{if?(stable)?{

bottomInset?=?mActionBarHeight;

}?else?{

bottomInset?=?mActionBarBottom.getMeasuredHeight();

}

}

}//?If?the?window?has?not?requested?system?UI?layout?flags,?we?need?to//?make?sure?its?content?is?not?being?covered?by?system?UI...?though?it//?will?still?be?covered?by?the?action?bar?if?they?have?requested?it?to//?overlay.mContentInsets.set(mBaseContentInsets);

mInnerInsets.set(mBaseInnerInsets);if?(!mOverlayMode?&&?!stable)?{

mContentInsets.top?+=?topInset;

mContentInsets.bottom?+=?bottomInset;

}?else?{

mInnerInsets.top?+=?topInset;

mInnerInsets.bottom?+=?bottomInset;

}//在ActionBar為非Overlay模式下,應用計算好的ContentInsetsapplyInsets(mContent,?mContentInsets,?true,?true,?true,?true);//if?(!mLastInnerInsets.equals(mInnerInsets))?{//?If?the?inner?insets?have?changed,?we?need?to?dispatch?this?down?to//?the?app's?fitSystemWindows().?We?do?this?before?measuring?the?content//?view?to?keep?the?same?semantics?as?the?normal?fitSystemWindows()?call.mLastInnerInsets.set(mInnerInsets);//Overlay模式下,將InnerInsets分發到子View中。?mContent.dispatchFitSystemWindows(mInnerInsets);}

measureChildWithMargins(mContent,?widthMeasureSpec,?0,?heightMeasureSpec,?0);

lp?=?(LayoutParams)?mContent.getLayoutParams();

maxWidth?=?Math.max(maxWidth,

mContent.getMeasuredWidth()?+?lp.leftMargin?+?lp.rightMargin);

maxHeight?=?Math.max(maxHeight,

mContent.getMeasuredHeight()?+?lp.topMargin?+?lp.bottomMargin);

childState?=?ViewUtils.combineMeasuredStates(childState,

ViewCompat.getMeasuredState(mContent));//?Account?for?padding?toomaxWidth?+=?getPaddingLeft()?+?getPaddingRight();

maxHeight?+=?getPaddingTop()?+?getPaddingBottom();//?Check?against?our?minimum?height?and?widthmaxHeight?=?Math.max(maxHeight,?getSuggestedMinimumHeight());

maxWidth?=?Math.max(maxWidth,?getSuggestedMinimumWidth());

setMeasuredDimension(

ViewCompat.resolveSizeAndState(maxWidth,?widthMeasureSpec,?childState),

ViewCompat.resolveSizeAndState(maxHeight,?heightMeasureSpec,

childState?<

}

根據上面的堆棧圖知道mContent是NativeActionModeAwareLayout類型,而NativeActionModeAwareLayout,沒有dispatchFitSystemWindows方法,那么查看其父類的dispatchFitSystemWindows方法。NativeActionModeAwareLayout的父類是ContentFrameLayout類型,看它的dispatchFitSystemWindows方法。

public?void?dispatchFitSystemWindows(Rect?insets)?{

fitSystemWindows(insets);

}

它直接調用View的fitSystemWindows方法。看View的fitSystemWindows方法。

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;

}try?{

mPrivateFlags3?|=?PFLAG3_FITTING_SYSTEM_WINDOWS;return?dispatchApplyWindowInsets(new?WindowInsets(insets)).isConsumed();

}?finally?{

mPrivateFlags3?&=?~PFLAG3_FITTING_SYSTEM_WINDOWS;

}

}?else?{return?fitSystemWindowsInt(insets);

}

}

由于第一次調用,這里的mPrivateFlags3 的PFLAG3_APPLYING_INSETS標志為不為1,所以進入if條件。進入dispatchApplyWindowInsets方法。并將mPrivateFlags3 的PFLAG3_APPLYING_INSETS標志為置為1。由于ContentFrameLayout繼承了Framelayout ,所以進入了ViewGroup的dispatchApplyWindowInsets方法。

@Overridepublic?WindowInsets?dispatchApplyWindowInsets(WindowInsets?insets)?{

insets?=?super.dispatchApplyWindowInsets(insets);if?(!insets.isConsumed())?{final?int?count?=?getChildCount();for?(int?i?=?0;?i?

insets?=?getChildAt(i).dispatchApplyWindowInsets(insets);if?(insets.isConsumed())?{break;

}

}

}return?insets;

}

首先調用了 super.dispatchApplyWindowInsets方法,也就是View的 dispatchApplyWindowInsets,

然后如果insets沒有被消費掉的話,分別調用每個view child的dispatchApplyWindowInsets方法,讓子view去消費它,如果子view消費了,那么到此結束。先執行 super.dispatchApplyWindowInsets方法。

下面是View.dispatchApplyWindowInsets方法。

public?WindowInsets?dispatchApplyWindowInsets(WindowInsets?insets)?{try?{

mPrivateFlags3?|=?PFLAG3_APPLYING_INSETS;if?(mListenerInfo?!=?null?&&?mListenerInfo.mOnApplyWindowInsetsListener?!=?null)?{return?mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this,?insets);

}?else?{return?onApplyWindowInsets(insets);

}

}?finally?{

mPrivateFlags3?&=?~PFLAG3_APPLYING_INSETS;

}

}

在此方法中首先將mPrivateFlags3 的PFLAG3_APPLYING_INSETS標志位置為1,然后如果開發者設置了listener的話就調用listener,否則調用onApplyWindowInsets方法。

public?WindowInsets?onApplyWindowInsets(WindowInsets?insets)?{if?((mPrivateFlags3?&?PFLAG3_FITTING_SYSTEM_WINDOWS)?==?0)?{if?(fitSystemWindows(insets.getSystemWindowInsets()))?{return?insets.consumeSystemWindowInsets();

}

}?else?{if?(fitSystemWindowsInt(insets.getSystemWindowInsets()))?{return?insets.consumeSystemWindowInsets();

}

}return?insets;

}

在第一次調用fitSystemWindows方法后,mPrivateFlags3 得 PFLAG3_FITTING_SYSTEM_WINDOWS標志為被置位1了,所以進入fitSystemWindowsInt方法。

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;

}

在這個方法中,兩個關鍵函數

computeFitSystemWindows

internalSetPadding

先看computeFitSystemWindows。官方解釋是,計算insets應該被此view消費掉還是繼續傳遞。

protected?boolean?computeFitSystemWindows(Rect?inoutInsets,?Rect?outLocalInsets)?{if?((mViewFlags?&?OPTIONAL_FITS_SYSTEM_WINDOWS)?==?0||?mAttachInfo?==?null||?((mAttachInfo.mSystemUiVisibility?&?SYSTEM_UI_LAYOUT_FLAGS)?==?0&&?!mAttachInfo.mOverscanRequested))?{

outLocalInsets.set(inoutInsets);

inoutInsets.set(0,?0,?0,?0);return?true;

}?else?{//?The?application?wants?to?take?care?of?fitting?system?window?for//?the?content...?however?we?still?need?to?take?care?of?any?overscan?here.final?Rect?overscan?=?mAttachInfo.mOverscanInsets;

outLocalInsets.set(overscan);

inoutInsets.left?-=?overscan.left;

inoutInsets.top?-=?overscan.top;

inoutInsets.right?-=?overscan.right;

inoutInsets.bottom?-=?overscan.bottom;return?false;

}

}

再看internalSetPadding

此方法是設置view的padding。

protected?void?internalSetPadding(int?left,?int?top,?int?right,?int?bottom)?{

mUserPaddingLeft?=?left;

mUserPaddingRight?=?right;

mUserPaddingBottom?=?bottom;final?int?viewFlags?=?mViewFlags;boolean?changed?=?false;//?Common?case?is?there?are?no?scroll?bars.if?((viewFlags?&?(SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL))?!=?0)?{if?((viewFlags?&?SCROLLBARS_VERTICAL)?!=?0)?{final?int?offset?=?(viewFlags?&?SCROLLBARS_INSET_MASK)?==?0??0?:?getVerticalScrollbarWidth();switch?(mVerticalScrollbarPosition)?{case?SCROLLBAR_POSITION_DEFAULT:if?(isLayoutRtl())?{

left?+=?offset;

}?else?{

right?+=?offset;

}break;case?SCROLLBAR_POSITION_RIGHT:

right?+=?offset;break;case?SCROLLBAR_POSITION_LEFT:

left?+=?offset;break;

}

}if?((viewFlags?&?SCROLLBARS_HORIZONTAL)?!=?0)?{

bottom?+=?(viewFlags?&?SCROLLBARS_INSET_MASK)?==?0??0?:?getHorizontalScrollbarHeight();

}

}if?(mPaddingLeft?!=?left)?{

changed?=?true;

mPaddingLeft?=?left;

}if?(mPaddingTop?!=?top)?{

changed?=?true;

mPaddingTop?=?top;

}if?(mPaddingRight?!=?right)?{

changed?=?true;

mPaddingRight?=?right;

}if?(mPaddingBottom?!=?bottom)?{

changed?=?true;

mPaddingBottom?=?bottom;

}if?(changed)?{

requestLayout();

}

}

總結

以上是生活随笔為你收集整理的android /system,android:fitSystemWindows详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。