日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Android view繪制流程詳解

瀏覽:28日期:2022-09-18 14:16:51
目錄繪制流程Measure 測量流程MeasureSpeclayout 布局流程draw 繪制流程相關類 & 概念DecorViewWindowViewRootActivity 視圖結構繪制流程 measure 流程測量出 View 的寬高尺寸。 layout 流程確定 View 的位置及最終尺寸。 draw 流程將 View 繪制在屏幕上。Measure 測量流程

系統是通過 MeasureSpec 測量 View 的,在了解測量過程之前一定要了解這個 MeasureSpec 。

MeasureSpec

MeasureSpec 是一個 32 位的 int 值打包而來的,打包為 MeasureSpec 主要是為了避免過多的對象內存分配。

為了方便操作,MeasureSpec 提供了快捷的打包和解包的快捷方法。

MeasureSpec.makeMeasureSpec( int size, int mode) MeasureSpec.getMode(int measureSpec) MeasureSpec.getSize(int measureSpec)

MeasureSpec 其中前 2 位表示測量的模式 SpecMode,后邊 30 位表示某種測量模式下的尺寸 SpecSize。

MeasureSpec 中有三種測量模式

UNSPECIFIED 不指定具體尺寸,完全由 View 自己發揮。 EXACTLY 精確模式,這種模式下使用后邊的 specSize ,一般對應于 LayoutParams 的 match_content 和設置的精確尺寸。 AT_MOST 最大模式,這種模式下 view 的最大尺寸不能超過后邊的 specSize ,一般對應于 LayoutParams 的 wrap_content

在測量 View 的時候,系統會將自己的 LayoutParams 參數在父容器的 MeasureSpec 影響下轉換為自己的MeasureSpec ,然后再通過這個 MeasureSpec 測量自身的寬高。

需要注意的是View 的MeasureSpec 不是唯一由 LayoutParams 決定的,是在父容器的共同影響下創建來的。

在 ViewGroup 的 measureChild() 可以看到具體的實現思路,getChildMeasureSpec() 里就是將 layoutParams 轉換為 measureSpec 的實現思路。

protected void measureChild(View child, int parentWidthMeasureSpec,int parentHeightMeasureSpec) {//拿到子元素的 LayoutParams 參數 final LayoutParams lp = child.getLayoutParams(); //創建子元素的 measureSpec final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); //將測量傳遞到子元素 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}public static int getChildMeasureSpec(int spec, int padding, int childDimension) { //解析父容器的 measureSpec ,解析出模式和尺寸 int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // 父容器是精確模式的情況,設置了精確尺寸。 case MeasureSpec.EXACTLY:if (childDimension >= 0) {//子元素本身是設置的精確尺寸,就是EXACTLY 模式,尺寸就是設置的尺寸。 resultSize = childDimension; resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) { // 子元素設置的 match_content 充滿入容器,就把尺寸設置為入容器的尺寸,模式設置為EXACTLY resultSize = size; resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.WRAP_CONTENT) { // 包裹模式下,子元素可以自己設置尺寸,但是不能超過夫容器的尺寸。模式為AT_MOST,尺寸為父容器的尺寸。 resultSize = size; resultMode = MeasureSpec.AT_MOST;}break; //父容器是最大模式 case MeasureSpec.AT_MOST:if (childDimension >= 0) { // 設置為子元素的尺寸,為精確模式 resultSize = childDimension; resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) { // 子元素想充滿父容器,應該設置為父容器的尺寸,但是父容器是最大模式,沒有精確尺寸。 // 所以將子元素設置為最大模式,不能超過父容器目前的尺寸。 resultSize = size; resultMode = MeasureSpec.AT_MOST;} else if (childDimension == LayoutParams.WRAP_CONTENT) { // 子元素沒有精確尺寸,想包裹自身,這種模式下,設置為最大模式,不超過父容器尺寸就好。 // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST;}break; // 父容器沒有限制,子元素自己發揮 case MeasureSpec.UNSPECIFIED:if (childDimension >= 0) { //子元素自己有設置的值,就好實用自己的值,設置為精確模式 resultSize = childDimension; resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) { // 子元素想充滿父容器,那就找到父容器的尺寸,但父容器的尺寸未知,還是要自己發揮 UNSPECIFIED。 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED;} else if (childDimension == LayoutParams.WRAP_CONTENT) { // 只元素是包裹自身,父容器無法給出參考,所以讓子元素自己去隨意發揮,仍然是UNSPECIFIED resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED;}break; } //使用打包方法,將子元素的模式和尺寸打包并返回 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}

measure 流程是在 ViewRoot 的 performMeasure() 里開始的。

在這里會將 DecorView 的 layoutParams 在 window 的 measureSpec 影響下轉換為自己的 measureSpec 。 然后調用 DecorView 的 measure() 將寬高的 measureSpec 傳入,在 measure() 里,decorView 開始自己的測量。

從 DecorView 的 measure() 開始,整個 View 樹的測量流程就開始了。

View 的測量都是在 measure() 里進行的,這是個 final 類型的方法,里面的實現比較簡單會有一些判斷調整,是否需要測量,會繼續調用 onMeasure() 將 measureSpec 傳進來,測量尺寸的確定最終是在 onMeasure() 里完成的。

通常我們自定義 View 都要重寫這個方法實現自己的測量邏輯,包括我們常用的控件都是自己重寫了這個方法實現自己的測量邏輯。

如果不重寫 onMeasure(),會導致自定義 view 的 wrap_content 參數無效,具體可以看一下 getDefaultSize() 實現。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED:result = size;break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY://默認 精確模式和最大模式下都是使用后邊的 specSize ,這會導致我們設置的 wrap_content 無效,始終是充滿父容器。result = specSize;break; } return result;}protected int getSuggestedMinimumHeight() { return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());} protected int getSuggestedMinimumWidth() { return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());}

View 和 ViewGroup 的測量過程是不同的。

單純的 View 只需要在 onMeasure() 里完成自己的測量就可以了,ViewGroup 除了完成自己的測量外,還有子元素的測量。

ViewGroup 的 onMeasure() 是沒有任何實現的,因為各個布局的特性不同,具體測量邏輯也是不同的,具體實現都在各個布局里。

但是 ViewGroup 里提供了 measureChildren() 方法,思路就是,遍歷所有需要顯示的子元素,取出他們的 LayoutParams 參數在自己 measureSpec 的影響下創建出子元素的 measureSpec ,然后將調用子元素的 measure() 將measureSpec 傳遞進去。

這里就將測量傳遞到了子元素。如果子元素是單純的 View 控件只需要完成自己就可以了,如果是 ViewGroup 會繼續將測量遞歸下去,直至完成整個 View 樹的測量。

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {final int size = mChildrenCount;final View[] children = mChildren;for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {//測量子元素,measureChild 見上面 MeasureSpec 里的代碼。measureChild(child, widthMeasureSpec, heightMeasureSpec); }} }

在完成測量流程之后就會進入了 layout 流程了。

layout 布局流程

layout 這一流程會確定 View 的四個頂點位置,進而確定在父容器中的位置和最終寬高。

layout 流程也是在 ViewRoot 里開始,是在 performLayout() 里首先調用 DecorView 的 layout() 方法開始整個 View 樹的布局流程。

View 的布局流程都是在 layout() 方法里完成的,會在這里通過 setFrame() 設置自己四個頂點的位置。

設置完自己的位置后,會繼續調用 onLayout() 方法,如果是 ViewGroup 可以繼續在 onLayout 里確定子元素的位置。

View 的 onLayout() 是沒有任何實現的,因為它是沒有子元素,ViewGroup 本身也是沒有實現的,也都是具體的各個布局里自己實現的。

思路也是遍歷所有需要布局的子元素,根據測量尺寸計算出他們的位置后調用子元素的 layout() 方法將位置參數穿進去,讓子元素去完成自己的布局流程。

在這里也是將布局流程傳遞到了子元素,如果子元素是 ViewGroup 會繼續將布局流程傳遞,直到完成整個 View 樹的布局流程。

layout() 確定自身的位置 onLayout() 確定子元素的位置

在完成 layout 流程后,就是最后一個 draw 流程了。

draw 繪制流程

這個流程是將 View 繪制到屏幕上。

draw 流程也是在 ViewRoot 里開始的,具體是在 performDraw() 里開始,在這里會調用 DecorView 的 draw() 開始整個 View 樹的繪制。

draw 的過程相對來說較為簡單,在 draw() 里可以看到整個步驟

繪制背景 drawBackground(canvas); 繪制自己的內容 onDraw(canvas); 繪制子元素 dispatchDraw(canvas); 繪制裝飾 onDrawForeground(canvas);

我們自定義 View 都會在 onDraw() 里實現自己的繪制邏輯,View 的 dispatchDraw() 是沒有任何實現的,具體實現在 ViewGroup 里。

在 ViewGroup 后調用子元素的 draw() 將繪制流程傳遞到子元素,直到繪制完整個 View 樹。

在完成整個 View 樹的繪制后,就可以在屏幕上看見界面了。

相關類 & 概念

在 View 的繪制過程中,涉及到了很多類,這里就不做詳細的介紹了,只在這里簡單列一下,知道這些個的作用。

DecorView

整個 View 樹的根節點,所有的繪制,事件都是從這個 View 開始分發的。

它繼承自 FrameLayout 是一個 ViewGroup ,內部含有一個 LinearLayout 。

這個 LinearLayout 里有一個 id 為 content 的 FrameLayout ,我們通常設置的 setContentView() 就是加載到了這個 FrameLayout 里。

Window

每個 Activity 都有一個 window ,直譯就是“窗口”,是 Activity 的成員變量,也是應用程序的視圖窗口,承載整個 Activity 的視圖。 內部含有一個 DeocrView 成員變量,承載的視圖就是這個 DeocrView 。

它目前只有一個實現類,PhoneWindow ,activity 里的 mWindow 就是這個實例。

ViewRoot

View Root 的作用很大,是連接 DecorView 和 Window Manager 的紐帶。 View 的繪制,觸屏,按鍵,屏幕刷新等事件分發都通過它完成的。

Activity 視圖結構

Android view繪制流程詳解

以上就是Android view繪制流程詳解的詳細內容,更多關于Android view繪制流程的資料請關注好吧啦網其它相關文章!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
99国产精品久久久久久久成人热| 久久成人亚洲| 日本亚洲欧洲无免费码在线| 在线观看免费一区二区| 精品免费av在线| 国产美女视频一区二区| 日韩在线观看中文字幕| 免费不卡在线观看| 在线观看一区| 涩涩涩久久久成人精品| 一区二区三区四区精品视频| 在线看片一区| 日韩中文av| 日韩欧美高清一区二区三区| 蜜臀av一区二区三区| 亚洲精品黄色| 日本午夜精品一区二区三区电影| 日韩国产精品久久久| 国产亚洲久久| 麻豆精品久久| 久久亚洲国产精品尤物| 国内精品伊人| 久久久夜精品| 亚洲经典在线| 中文字幕亚洲精品乱码| 精品国产一区二| 日韩大片免费观看| 好看的av在线不卡观看| 亚洲日产av中文字幕| 国产乱人伦精品一区| 成人在线免费观看网站| 午夜精品婷婷| 久久国产麻豆精品| 日韩国产一区二区| 最新亚洲一区| 97久久超碰| 日韩综合一区| 亚洲一区欧美激情| 久久一区精品| 欧美日韩精品一本二本三本| 日韩精品免费观看视频| 国产一区二区三区不卡视频网站| 国户精品久久久久久久久久久不卡 | 国产在线不卡一区二区三区| 精品国产亚洲日本| 久久三级中文| 久久精品亚洲欧美日韩精品中文字幕| 国产66精品| 91嫩草亚洲精品| 免费在线观看一区| 高清一区二区三区av| 成人在线网站| 国产免费成人| 欧美日韩一区自拍| 国产成人精品三级高清久久91| 中文字幕高清在线播放| 欧美日韩激情| 日韩一区网站| 精品视频在线观看网站| 日韩欧美一区免费| 亚洲黄色在线| 日韩国产欧美三级| 国产精品久久国产愉拍| 日韩欧美国产精品综合嫩v| 亚洲成人免费| 亚洲精品麻豆| 国产伦精品一区二区三区千人斩| 久久亚洲国产精品一区二区| 国产精品午夜一区二区三区| 激情国产在线| 欧美午夜不卡影院在线观看完整版免费| 亚洲精品国模| 福利欧美精品在线| 在线综合欧美| 欧美黄页在线免费观看| 日韩精品麻豆| 日韩亚洲精品在线观看| 欧美精品二区| 亚洲欧洲午夜| 久久99性xxx老妇胖精品| 国产在线日韩| 欧美精品中文| 99精品一区| 青草国产精品| 香蕉久久精品| 国产精品久久久久久久久久齐齐 | 日本在线成人| 欧美xxxx中国| 欧美色综合网| 激情丁香综合| 国产欧美在线观看免费| 久久九九精品| 国产精品免费99久久久| 夜久久久久久| 精品99在线| 蜜桃久久精品一区二区| 久久精品三级| 国产精品婷婷| 中文字幕一区久| 亚洲精品一二| sm久久捆绑调教精品一区| 老司机精品久久| 色一区二区三区四区| 亚洲最大av| 日韩一区二区三区在线免费观看| 日韩高清在线观看一区二区| 99久久九九| 国产精品天堂蜜av在线播放| 日韩中文字幕1| 成人看片网站| 精品在线网站观看| 蜜臀国产一区二区三区在线播放| 中文字幕系列一区| 美女性感视频久久| 亚洲人成网77777色在线播放| 狠狠躁少妇一区二区三区| 日韩精品中文字幕吗一区二区 | 欧美sm一区| 麻豆一区二区在线| 亚洲欧美网站在线观看| 亚洲精品成人| 在线人成日本视频| 国产欧美69| 亚久久调教视频| 午夜国产精品视频| 日韩三区在线| 成人台湾亚洲精品一区二区| 日韩激情一区二区| 国产精品嫩草99av在线| 久久久久91| www.51av欧美视频| 麻豆高清免费国产一区| 欧美日韩黄网站| 综合精品一区| 久久一二三区| 国产偷自视频区视频一区二区| 99久久九九| 日本高清不卡一区二区三区视频| 精品久久不卡| 欧美国产免费| 国产欧美自拍| 欧美亚洲二区| 91亚洲无吗| 老色鬼久久亚洲一区二区| 欧美成人综合| 欧美中文一区二区| 久久久一本精品| 青青久久av| 99精品视频在线| 三级精品视频| 美女网站视频一区| 成人免费一区| 久久在线免费| 欧美精品黄色| 国产亚洲精品自拍| 羞羞答答国产精品www一本| 在线国产一区二区| 国产偷自视频区视频一区二区| 亚洲午夜久久久久久尤物| 久久高清精品| 欧美日韩国产亚洲一区| 在线精品小视频| 在线免费观看亚洲| 久久99精品久久久久久园产越南| 欧美国产日本| 色婷婷综合网| 精品日韩视频| 午夜久久福利| 亚洲香蕉久久| 日本久久二区| 欧美激情五月| 久久久久久夜| 在线天堂中文资源最新版| 激情视频网站在线播放色| 欧美日韩免费观看视频| 99视频精品视频高清免费| 亚洲精品成人| 亚州精品视频| 久久伊人国产| 日韩精品诱惑一区?区三区| 激情久久五月| 蜜芽一区二区三区| 国产伦一区二区三区| 国产精品久久久免费| 国产v日韩v欧美v| 天堂资源在线亚洲| 免费视频一区二区| 国产精品一区二区中文字幕| 欧美精品91| 视频福利一区| 一区二区三区午夜视频| 国产精品二区影院| 三级精品视频| 在线看片日韩| 欧美日一区二区三区在线观看国产免 | 一区免费视频| 国产探花一区| 日本精品影院| 久久高清国产| 国产极品一区|