乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      View 的繪制過程

       Coder編程 2022-01-04

      View的繪制.png

      基本概念介紹

      • Activity:一個 Activity 是一個應(yīng)用程序組件,提供一個屏幕,用戶可以用來交互。

      • View:所有視圖控件的基類

      • ViewGroup:View 的子類,是容器類控件,內(nèi)部用于放置子View

      • Window:概況了 Android 窗口的基本屬性和基本功能(抽象類)

      • PhoneWindow:Window 的實現(xiàn)類

      • DecorView: 界面的 根 View,PhoneWindow 的內(nèi)部類,F(xiàn)rameLayout 的子類

      • ViewRootImpl:官方定義是 The top of a view hierarchy,implementing the needed protocol between View and the WindowManager. 在 View 層級中的頂層,可以認(rèn)為是 View 樹的根(注意 ViewRootImpl 不是 View,只是根,DecorView 是根 View,屬于 View)用于串聯(lián) Window 和 View視圖

      • WindowManager:是用來管理窗口的(Window)它的實現(xiàn)對象是 WindowManagerImpl,內(nèi)部的大部分方法真正的實現(xiàn)是 WindowMangerGlobal

      • WindowManagerService:簡稱 WMS,作用是管理所有應(yīng)用程序中的窗口


      Android頁面來自網(wǎng)絡(luò).png

      Activity 啟動過程簡單介紹

      Activity 設(shè)置頁面布局的過程

      1. 在 ActivityThread 主線程中 newActivity 生成一個 Activity

      2. 然后調(diào)用 Activity 的attach 方法,attach 方法中生成 PhoneWindow 對象

      3. setContentView 中初始化 DecorView (ViewGroup 的子類)其實真正的執(zhí)行是在 PhoneWindow 中的 setContentView

      4. 在 LayoutInflater 中對布局文件進行 xml 解析獲取對象的數(shù)據(jù)

      5. 根據(jù)解析出的數(shù)據(jù)執(zhí)行 View 的構(gòu)造函數(shù)進行 View 的創(chuàng)建。

        上面內(nèi)容是在 onCreate() 中執(zhí)行完成的

      6. 然后在 onResume 執(zhí)行完成后調(diào)用View的繪制

      詳細的說明看:Activity 從啟動到布局繪制的簡單分析

      View 的繪制

      View 的繪制流程可以分成三步:測量、布局、繪制

      分別對應(yīng)了:onMeasure() onLayout() onDraw 當(dāng)然這個過程中也會調(diào)用許多其他的方法,都是作為輔助,大的流程就這三步。其中這三步內(nèi)部的執(zhí)行都是呈現(xiàn)樹狀結(jié)構(gòu),從根 View 開始循環(huán)遞進,直到所有子 View 全部執(zhí)行完畢。

      測量 onMeasure

      onMeasure(int widthMeasureSpec,int heightMeasureSpec) 這個方法對于單控件來說,只是測量他自己,但是對于 ViewGroup 來說還要正確的給它的子控件傳入期望的測量數(shù)值。然后根據(jù)所有子控件的大小和 onMeasure 中的參數(shù)來設(shè)置自己本身的大小。

      關(guān)于 MeasureSpec 就不多解釋了,這里只說一下內(nèi)部的三種模式

      • MeasureSpec.EXACTLY 意思是精確大小,當(dāng)你想給這個 View 一個精確的大小的時候就是用這個參數(shù),比如布局中指定了大小是 10 dp 或者 match_parent 都是屬于這種類型的

      • MeasureSpec.AT_MOST 意思是父布局會給一個最大的值,大小不能超過這個值(就是定義的這種標(biāo)準(zhǔn),當(dāng)然你不按照這個標(biāo)準(zhǔn),在自己寫 onMeasure() 的時候,明明父布局給的類型是 AT_MOST 你還要超過,那也沒事,只是布局的樣子可能就會有問題了)。對應(yīng) wrap_content 模式

      • MeasureSpec.UNSPECIFIED 意思沒有指定尺寸,這種情況不常見,一般都是父控件是 AdapterView 通過 measure 方法傳入模式。

      關(guān)于 ViewGroup 的自定義,onMeasure() 方法內(nèi)部需要實現(xiàn)什么?

      首先我們需要給這個控件設(shè)置正確的期望大小 setMeasuredDimension(width,height) 要想正確的獲取 width 和 height 還需要根據(jù) onMeasure(int widthMeasureSpec,int heightMeasureSpec) 中的參數(shù)來確定。如果給的參數(shù)類型是 EXACTLY 的話,說明它的父控件給他的大小是確定的,這個時候的大小就填寫參數(shù)中的數(shù)值大小就好(需要 MeasureSpec.getSize(int))。如果參數(shù)類型是 AT_MOST 的時候,這個表示父布局給了一個值,當(dāng)前的 View 的大小不能超過這個值。那么我們就需要自己計算出這個 View 想要的大小,然后和父布局給的最大的值做比較,選擇一個值給 setMeasuredDimension()

      那么如何獲取此 ViewGroup 的正確高度呢?做法就是要獲取到每個子View 的高度和一些 padding Margin 加起來就是這個 ViewGroup 應(yīng)該的高度了。

      要想獲取子 View 的高度就需要調(diào)用 child.measure() 然后 child.getMeasureHeight 就獲取 Child 的高度了。也就是說需要我們給子 View 測量一下,測量的時候我們需要傳入值。當(dāng)然這個值也不是隨便傳入的,如果你隨便傳入的話,那么 child 的大小就亂了,和你在布局文件中設(shè)定的大小就不一樣了。

      那么如果正確的給 child 傳入值呢?LinearLayout 是這樣做的,當(dāng)然我們可以根據(jù)我們想要的布局來進行自定義。

      // 核心代碼

      // count 是 child 的個數(shù)
      for(int i=0;i<count;i++){
          // 獲取 child 的 LayoutParmas 這個對象有我們在 xml 中給 view 設(shè)置的大小信息
      	final LayoutParams lp = (LayoutParams)child.getLayoutParams();
          // 然后根據(jù) LayoutParams 中的參數(shù)和 ViewGroup本身的 widthMeasureSpec 來進行對比,選擇一個合適的數(shù)值給
          // child LinearLayout 具體的做法是通過 
          //  ViewGroup 中的 getChildMeasureSpec 方法來獲取一個合適值
          
      }
      
      
      // ViewGroup 中的 getChildMeasureSpec(int spec,int padding,int childDimension) 方法的實現(xiàn)代碼
      
      // spec 是 onMeasure 中的 spec padding 是子View 的margin + 父控件的 padding  childDimension 是子 View 在布局文件中給定的大小
      public static int getChildMeasureSpec(int spec,int padding,int childDimension){
          int specMode = MeasureSpec.getMode(spec);
          int SpecSize = MeasureSpec.getSize(spec);
          // 得出 ViewGroup 實際可以使用的大小
          int size = Math.max(0,specSize-padding);
          
          int resultSize = 0;
          int resultMode = 0;
          // 然后就是根據(jù) specMode 和 childDimension 來得出合適的大小。
      }

      布局 onLayout

      onLayout 對于子控件來說沒有什么意義,對于 ViewGroup 來說,onLayout 方法內(nèi)部要對子控件進行布局,調(diào)用子控件的 layout 函數(shù)。

      onLayout 重寫的時候,只需要獲取子 View 的實例,然后調(diào)用子 View 的 layout 方法來實現(xiàn)布局就可以了,具體 layout 中傳入的參數(shù),是重寫 onLayout 的重點。需要通過 getMeasureHeight 等獲取子 View 的理想高度,然后再根據(jù)具體情況傳入數(shù)值。

      繪制 onDraw

      onDraw() 函數(shù)就是來繪制了,一般 ViewGroup 不會實現(xiàn)內(nèi)部的方法,子控件才重寫 onDraw() 方法。也是內(nèi)部一層層分發(fā)繪制。呈現(xiàn)樹狀結(jié)構(gòu)

      // 最根部調(diào)用下面的方法
      // public void draw(Canvas canvas);
      // 然后此方法內(nèi)部調(diào)用 onDraw()(針對于 子View的)dispatchDraw(Canvas canvas) (主要是針對于 ViewGroup 的)
      // 然后 dispatchDraw() 內(nèi)部會調(diào)用 drawChild(Canvas canvas,View child,long drawingTime) 然后此方法內(nèi)部會執(zhí)行 draw 方法,就這樣一層一層下去了。如果最終到了子View就會終止,因為子View dispatchDraw 方法體是空的。
      
      //

      另外可以認(rèn)為這三個方法都對應(yīng)著 measure()、layout() draw() 方法??梢哉J(rèn)為這三個方法內(nèi)部調(diào)用了上面的方法。

      上面 onMeaure onLayout onDraw() 都介紹完了,那么最根處的 View 是怎么調(diào)用的呢?

      布局樹.png

      可以看到上面這張圖,追溯到根View DecorView ,其實最開始就是 ViewRootImp 來調(diào)用 DecorView 的 measure() ,并且傳入了具體的值,這個值一般就是頁面的大小。然后在 DecorView 的 measure 方法內(nèi)部會調(diào)用 onMeasureonMeasure 的內(nèi)部又會調(diào)用它的子 View 的 measure 然后就這樣一層層的下去了,直到所有子 View 執(zhí)行完畢,DecorView 的 measure 就執(zhí)行完畢了,到此整個頁面的測量工作完成。

      onLayout 也是最先 ViewRootImp 來調(diào)用 DecorView 的 layout() 開始。onDraw 也是最先 ViewRootImp 來調(diào)用 DecorView 的 draw() 開始的。然后 draw() 的內(nèi)部的執(zhí)行就和上面介紹 onDraw() 中一樣了

      到此整個頁面的測量、布局、繪制就全部分析完畢了。

      可以查看:Activity 從啟動到布局繪制的簡單分析

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多