天天看點

【View工作原理】ViewRoot、DecorView、MeasureSpec和LayoutParams

一、視窗層級關系

【View工作原理】ViewRoot、DecorView、MeasureSpec和LayoutParams

1、PhoneWindow

  • 是Android中最基本的視窗系統,每個Activity會建立并持有一個PhoneWindow對象,是Activity和整個View系統互動的接口。

2、DecorView

  • 1、Dispatch ViewRoot分發來的key、touch、trackball等外部事件。
  • 2、DecorView有一個直接的子View,我們稱之為System Layout,這個View是從系統的Layout.xml中解析出的,它包含目前UI的風格,如是否帶title、是否帶process bar等。
  • 3、作為PhoneWindow與ViewRoot之間的橋梁,ViewRoot通過DecorView設定視窗屬性。

3、System Layout

  • 目前android根據使用者需求預設了幾種UI 風格,通過PhoneWindow通過解析預置的layout.xml來獲得包含有不同Window decorations的layout,我們稱之為System Layout,我們将這個System Layout添加到DecorView中。
  • 預設風格可以通過PhoneWindow方法requestFeature()來設定,需要注意的是這個方法需要在setContentView()方法調用之前調用。

4、Content Parent

  • Content Parent這個ViewGroup對象才是真真正正的ContentView的parent,我們的ContentView終于找到了寄主,它其實對應的是System Layout中的id為“content”的一個FrameLayout。這個FrameLayout對象包括的才是我們的Activity的layout。

5、Activity Layout

  • ActivityLayout就是我們通過SetContentView設定的Layout,是真正和使用者互動的部分。

二、ViewRoot

  • ViewRoot是GUI管理系統與GUI呈現系統之間的橋梁,根據ViewRoot的定義,我們發現它并不是一個View類型,而是一個Handler。
  • 它的主要作用如下:
    • 1、向DecorView分發收到的使用者發起的event事件,如按鍵,觸屏,軌迹球等事件;
    • 2、與WindowManagerService互動,完成整個Activity的GUI的繪制。View的三個流程都是通過ViewRoot來完成的。

三、MeasureSpec

  • 一個MeasureSpec封裝了父布局傳遞給子布局的布局要求,每個MeasureSpec代表了一組寬度和高度的要求。一個MeasureSpec由大小和模式組成。它有三種模式:UNSPECIFIED(未指定),父元素部隊自元素施加任何束縛,子元素可以得到任意想要的大小;EXACTLY(完全),父元素決定自元素的确切大小,子元素将被限定在給定的邊界裡而忽略它本身大小;AT_MOST(至多),子元素至多達到指定大小的值。
  • 它常用的三個函數:
    • 1、static int getMode(int measureSpec):根據提供的測量值(格式)提取模式(上述三個模式之一)
    • 2、static int getSize(int measureSpec):根據提供的測量值(格式)提取大小值(這個大小也就是我們通常所說的大小)
    • 3、static int makeMeasureSpec(int size,int mode):根據提供的大小值和模式建立一個測量值(格式)

四、LayoutParams

  • LayoutParams封裝的是View向父容器傳達自己意願的資訊,它封裝了Layout的位置、高、寬等資訊,表達自己想變成一個什麼尺寸的View。
  • 使用示例:
SwipeRefreshLayout refreshLayout = new NsRefreshLayout(this);
        refreshLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        ScrollView scrollView = new ScrollView(this);
        TextView textView = new TextView(this);
        textView.setText("TextView");
        scrollView.addView(textView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        refreshLayout.addView(scrollView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));