自定義View從實現到原理(二)- 源碼解析Activity的構成

自定義View從實現到原理(二)

View的分發機制在自定義View中屬於比較重要的一部分,在這之前,我們有必要了解一下Activity的組成,然後從源碼的角度分析View的事件分發機制。

源碼解析Activity的構成

我們都知道,點擊事件使用MotionEvent來表示的,在一個點擊事件發生之後,首先會傳到Activity,那麼我們首先要了解一下Activity的構成,在我們寫Activity的時候,都會用到類似這個語句來加載對應的佈局文件:

setContentView(R.layout.activity_app_start);

在setContentView這個方法中,源碼有一句我們需要注意:

public void setContentView(@LayoutRes int layoutResID) {
   
   
        getWindow().setContentView(layoutResID);
        ****
    }

是由getWindow()這個方法實現的setContentView(),那麼這個getWindow()這個方法又代表着什麼呢:

public Window getWindow() {
   
   
		return mWindow;
	}

可以看到getWindow()這個方法返回了一個Window變量mWindow,繼續查看代碼找到這個mWindow的賦值在哪裏,在Activity的attach()方法中:

mWindow = new PhoneWindow(this);

mWindow被初始化爲PhoneWindow,結合上面的

getWindow().setContentView(layoutResID);

這行代碼,就可以理解爲是Activity的setContentView方法是調用了PhoneWindow類中的setContentWindow()方法,我們來看一下這個方法的關鍵代碼:

if(mContentParent == null){
   
   
		installDecor();
	}
	****

看一下installDecor()的方法代碼:

if(mDector == null) {
   
   
		mDecor = generateDecor();//1
		****
	}
	
if(mContentParent == null){
   
   
		mContentParent = generateLayout(mDector);//2
		****
	}	

首先查看1處的代碼,generateDector()的代碼:

protect DecorView generateDecor() {
   
   
		return new DecorView(getContext() , -1);
	}

在這裏我們創建了一個DecorView的實例,這個DecorView其實就是Activity中的根View,查看這個DecorView的代碼我們可以看出他是PhoneWindow的內部類,並且繼承了FrameLayout。

返回上面的代碼,我們查看2中generateLayout()方法代碼,我們可以知道的是,這個方法的主要作用是根據不同的情況加載不同的佈局給layoutResource,類似這樣幾行代碼:

/**
* 幾種在源碼中加載佈局的代碼
*/
//1
layoutResource = R.layout.screen_title;

//2
layoutResource = R.layout.screen_title_icons;
****

等等類似這種的代碼有多種,我們就看一下第一種 R.layout.screen_title的佈局代碼:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

這個文件在Frameworks,上面的ViewStub是用來顯示ActionBar的,下面的兩個FrameLayout,一個是用來顯示標題title,一個是用來顯示內容Content。

經過閱讀以上的這些源碼,我們梳理一下Activity的組成:
1.Activity中包含setContentView(*)方法,用來加載佈局文件;
2.Activity的setContentView()是由一個Window對象實現其自身的setContentView()完成的;
3.這個Window對象本質上來說是一個PhoneWindow對象
4.PhoneWindow對象,設置了Activity的根View:DecorView
5.PhoneWindow中的方法,會根據不同的情況爲DecorView進行處理:
如加載了R.layout.screen_title佈局,則會將DecorView分成兩個區域,一個是Title一個是Content,我們平常所寫的佈局正是展示在ContentView部分的;





這篇就寫到這裏,下一篇會開始源碼解析View的事件分發機制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章