日韩性视频-久久久蜜桃-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详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 亚洲激情另类 | 一级做a爰片久久毛片 | 嫩草视频在线看 | 欧美激情片在线观看 | 青青草网站 | 白丝校花扒腿让我c | 国产在线综合视频 | 丰满肉嫩西川结衣av | 玖玖在线观看 | 6699嫩草久久久精品影院 | 古装做爰无遮挡三级视频 | 最新免费av网站 | 久久久久国产一区二区 | 亚洲国产私拍精品国模在线观看 | 秋霞成人午夜鲁丝一区二区三区 | 五月婷婷六月丁香综合 | 轻轻草在线视频 | 中日韩男男gay无套 人人草人人干 | 日韩一级片免费 | 成人a级网站 | 伊人免费 | av在线网址观看 | 三上悠亚在线观看一区二区 | 午夜激情免费视频 | 天堂网av在线 | 明星毛片 | 国产精品腿扒开做爽爽爽挤奶网站 | 亚洲第七页 | 国产男女啪啪 | 成人黄网免费观看视频 | 91青青视频| 亚洲AV无码国产精品午夜字幕 | 人人超碰人人 | 成人黄色一级 | 寂寞人妻瑜伽被教练日 | 77久久 | 巨乳中文字幕 | 黄色大片日本 | 国产在线看一区 | 国产成人精品无码免费看夜聊软件 | 末路1997全集免费观看完整版 | 这里有精品视频 | 久久国产热 | 中文字幕日本在线 | av片免费 | 亚洲黄色片 | 女王脚交玉足榨精调教 | 精品国产乱码久久久久久免费 | 国产精品18久久久久久vr下载 | 麻豆亚洲 | 91黄色视屏 | 先锋影音一区二区三区 | 午夜精品福利一区二区三区蜜桃 | 在线欧美日韩 | 日本a免费 | 中文永久免费观看 | 狠狠干天天干 | 欧美成人极品 | 亚洲一区二区人妻 | 亚洲成人av一区二区三区 | 成人综合久久 | 人妻丰满熟妇av无码区hd | 美女脱了裤子让男人桶 | 日日夜夜精品免费视频 | 四虎成人av | 麻豆成人免费 | 国产a级大片 | 在线免费a视频 | 亚洲国产视频网站 | 一区二区三区四区五区在线视频 | 久久综合激情 | 国产av天堂无码一区二区三区 | 一路向西在线看 | 麻豆爱爱 | 美国黄色av | 精品无码人妻少妇久久久久久 | 日本在线不卡一区 | 亚洲欧美另类激情 | 日日日日操 | 免费成人结看片 | 美女久久久久久 | 天天干天天操天天干 | 日韩精品中文字 | 好吊操这里只有精品 | 亚洲精品一区二区三区在线 | 无码内射中文字幕岛国片 | 国产超碰在线观看 | 91黄漫 | 男男一级淫片免费播放 | 得得的爱在线视频 | 久久婷婷热 | 欧美老熟妇乱大交xxxxx | av手机天堂 | 欧美一级做a爰片久久高潮 久热国产精品视频 | 亚洲欧美日韩系列 | 国产主播福利在线 | 午夜草草 | 精品免费一区二区三区 | 黄色三级三级三级 |