<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 什么是 ViewRootImpl 相比 Viewgroup 和 View,ViewRootImpl 可能更為陌生,實際開發中我們基本用不到它。那么 > 什么是 ViewRootImpl 呢? 從結構上來看,ViewRootImpl 和 ViewGroup 其實是一種東西 ![](https://img.kancloud.cn/87/5c/875c1faf3ef7ea479e1d969e2ffe6272_1500x400.png) 它們都繼承了 ViewParent。ViewParent 是一個接口,定義了一些父 View 的基本行為,比如 requestlayout,getparent 等。不同的是,ViewRootImpl 并不會像 ViewGroup 一樣被真正繪制在屏幕上。在 activity 中,它是專門用來繪制 DecorView 的,核心方法是 setView ## “activity,window,View 三者之間的關系是什么?” 我們可以通過一張圖來說明。 ![](https://img.kancloud.cn/89/25/8925c9c22b24f3461dce89cace67b68c_612x810.png) 如圖所示,window 是 activity 里的一個實例變量,本質是一個抽象類,唯一的實現類是 PhoneWindow。 activity 的 setContentView 方法實際上是就是交給 phonewindow 去做的。window 和 View 的關系可以類比為**顯示器**和**顯示的內容**。 每個 activity 都有一個“顯示器”**window**,“顯示的內容”就是**DecorView**。這個“顯示器”定義了一些方法來決定如何顯示內容。比如 setTitleColor setTitle 是設置導航欄的顏色和 title , setAllowReturnTransitionOverlap 設置進/出場動畫等等。 所以**window 是 activity 的一個成員變量,window 和 View 是“顯示器”和“顯示內容”的關系。** 這就是他們的關系 ## View 是怎么繪制的 ### onCreate 在整個 activity 的生命周期中,setContentView 是在 onCreate 中調用的,它實現了對資源文件的解析,完成了 xml 文件到 View 的轉化。期呢? ### onResume 真正開始繪制 他們的關系在源碼中一目了然。 ![](https://img.kancloud.cn/0d/37/0d37f65f3893b3ed8826bf588fed8ab2_1702x2710.png) 從源碼中可以看到,onResume 之后,ActivityThread 通過調用 activity 中 windowmanager 的 addView 方法,將 decorView 傳入到 ViewRootImpl 的 setView 方法中,通過 setView 來完成 View 的繪制。 問題又來了,setView 到底有什么魔法,為什么他就能完成 View 的繪制工作呢? ## ViewRootImpl 是如何繪制 View 的 我們再來看一下 setView 方法 ![](https://img.kancloud.cn/31/f2/31f20eb0aaae8d0386e1d12a0f36524b_1584x2248.png) 簡單來說 setView 做了三件事 ① 檢查繪制的線程是不是創建 View 的線程。這里可以引申出一個問題,View 的繪制必須在主線程嗎? ② 通過同步屏障保證繪制 View 的任務是最優先的 ③ 調用 performTraversals 完成 measure,layout,draw 的繪制 看到這里,ViewRootImpl 的繪制基本就完成了。其實這也是面試官希望聽到的內容。考察的是面試者對 View 繪制體系的理解。 后續 ViewGroup 和 View 的繪制其實是 performTraversals 對整個 ViewTree 的繪制。他們的關系可以用下面這張圖表示 ![](https://img.kancloud.cn/c1/1b/c11b40772b9d0b41b5f2d2e3235cabed_1408x940.png) ### mChoreographer —ViewRoot類的requestLayout()方法 —scheduleTraversals() —mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)請求刷新信號 —mChoreographer內部handler通過msg機制觸發mTraversalRunnable 啟動performTraversals();測繪流程 ## 為什么我在 onCreate 中調用 View.post > “不錯不錯,看來你對 Viewrootimpl 的繪制過程掌握的不錯嘛,你剛才提到 View 的繪制是在 onResume 之后才開始的,那為什么我在 onCreate 中調用 View.post 方法可以得到 View 的寬高呢” 這個問題乍看挺唬人的。其實看一眼源碼大概就明白了 ![](https://img.kancloud.cn/8c/40/8c403e5c38cf6cb52f0957a99ef6da07_1020x610.png) View.post 會判斷當前 View 是否已經被添加到 window 上。如果添加了則立即執行 runnable,如果沒有被添加則先放到一個隊列中存儲起來,等添加到 window 上時再執行。 而 View 被測量完成后才會 attachToWindow。所以當 post 的 runnable 執行時,View 已經繪制完成了。 ## MeasureSpec 的理解 View 的大小不僅僅取決于自身的寬高,還取決于父 View 的大小和測量模式。一個 200*200 的父 View 是不可能容納一個 300*300 的子 View 的,父 View 的 wrap\_content 和 match\_content 也會影響子 View 的大小。 所以 View 的 measure 函數其實應該有 4 個參數:**父 View 的寬**,**父 View 的高**,**寬的測量模式**,**高的測量模式**。 Android 這里用了一個巧妙的設計,用一個 Int 值來表示寬/高的測量模式和大小。一個 int 有 32 位,前 2 位表示測量 MODE,后 30 位表示 SIZE。 為什么要用 2 位表示 MODE 呢?因為 MODE 只有 3 種呀,UNSPECIFIED,EXACTLY,AT_MOST * 精確模式 EXACTLY:父 View 指定了子 View 確切的大小 * 最大模式 AT_MOST:父 View 指定一個大小,子 View 不能超過這個值 * 未指定模式 UNSPECIFIEND: 父 View 不對子 View 有任何限制 ### 我自定義一個 View 的時候,如果不對 MeasureSpec 做處理。使用這個 View 時寬高傳入 wrap\_content,結果會怎么樣?” 這個考察的就是 View 繪制的實際運用了。當我們自定義一個 View 時,如果繼承的是 View,measure 方法走的就是 View 默認的邏輯 ![](https://img.kancloud.cn/c7/c9/c7c955b7ce49a425a593f797cd3e4586_1584x1156.png) 所以當我們自定義 View 時,如果沒有對 MODE 做處理,設置 wrap\_content 和 match\_content 結果其實是一樣的,View 的寬高都是取父 View 的寬高。 ## invaliate 和 requestlayout 方法的區別 前面我們說到,ViewRootImpl 作為頂級 View 負責 View 的繪制。所以簡單來說,requestlayout 和 invaliate 最終都會向上回溯調用到 ViewRootImpl 的 postTranversals 方法來繪制 View。 不同的是 requestlayout 會繪制 View 的 measure,layout 和 draw 過程。invaliate 因為只添加了繪制 draw 的標志位,只會繪制 draw 過程。 ##參考資料 [【面試官爸爸】來給我講講View繪制?](https://juejin.cn/post/6979395482946633758)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看