先看看 view 基于整個屏幕分布的概況
首先要明確view是屏幕繪制的入口
那么View的繪制是從哪里開始的呢次企,我們知道每個Activity 均會創(chuàng)建一個PhoneWindow對象腕够,
是Activity和整個View系統(tǒng)交互的接口剩彬,每個Window都對應著一個View和一個ViewRootImpl,
Window和View通過ViewRootImpl來建立聯(lián)系,對于Activity來說撮珠,ViewRootImpl是連接
WindowManager和DecorView的紐帶,繪制的入口是由ViewRootImpl的performTraversals方法
來發(fā)起Measure酱酬,Layout实柠,Draw等流程的丙曙。。
再來個圖來補充一下PhoneWindow:
整個流程的大致流程圖:
看看源碼:
private void performTraversals() {
......
//最外層的根視圖的widthMeasureSpec和heightMeasureSpec由來
//lp.width和lp.height在創(chuàng)建ViewGroup實例時等于MATCH_PARENT
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
......
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
......
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
......
mView.draw(canvas);
......
}
概況了解清楚了那么翅萤,來具體看看
measure()恐疲、layout()、draw()的具體流程
measure()
首先看看其整體的過程
開始measure之前要明確一個概念MeasureSpec(測量規(guī)格),MeasureSpec是一個大小跟模式的組合值培己,控件自身的大小是受到MeasureSpec下的mode,size兩個值共同來決定的
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
widthMode=MeasureSpec.getMode(widthMeasureSpec);
hightMode=MeasureSpec.getMode(heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
hight = MeasureSpec.getSize(heightMeasureSpec);
}
就是在子控件正要放置自己的位置時糜烹,父控件會通過MeasureSpec這個對象來問子控件,“你想要用多大地方笆?”诸迟;然后子控件通過一系列的操作來放置控件茸炒!
MeasureSpec的mode一共有三種模式:
UPSPECIFIED : 父容器對于子容器沒有任何限制,子容器想要多大就多大
EXACTLY: 父容器已經(jīng)為子容器設置了尺寸,子容器應當服從這些邊界,不論子容器想要多大的空間。
AT_MOST:子容器可以是聲明大小內(nèi)的任意大小
根據(jù)mode,size 共同決定的子控件最終的大姓笪:
父View的MeasureSpec 是EXACTLY壁公,說明父View的大小是確切的,(確切的意思很好理解绅项,如果一個View的MeasureSpec 是EXACTLY紊册,那么它的size 是多大,最后展示到屏幕就一定是那么大)快耿。
父View的MeasureSpec 是AT_MOST囊陡,說明父View的大小是不確定,最大的大小是MeasureSpec 的size值掀亥,不能超過這個值撞反。
父View的MeasureSpec 是UNSPECIFIED(未指定),表示沒有任何束縛和約束,不像AT_MOST表示最大只能多大搪花,不也像EXACTLY表示父View確定的大小遏片,子View可以得到任意想要的大小,不受約束
好了 這是大概的流程撮竿,下面來個具體的示例:
布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:background="@android:color/holo_blue_dark"
android:paddingBottom="70dp"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/material_blue_grey_800"
android:text="TextView"
android:textColor="@android:color/white"
android:textSize="20sp" />
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@android:color/holo_green_dark" />
</LinearLayout>
屏幕顯示樣式如下:
整個圖是一個DecorView,DecorView可以理解成整個頁面的View,DecorView是一個FrameLayout,包含兩個子View吮便,一個id=statusBarBackground的View和一個是LineaLayout,id=statusBarBackground的View幢踏,而這個LinearLayout比較重要髓需,它包含一個title和一個content,title很好理解其實就是TitleBar或者ActionBar,content 就更簡單了惑折,setContentView()方法你應該用過吧授账,android.R.id.content 你應該聽過吧,沒錯就是它,content是一個FrameLayout惨驶,你寫的頁面布局通過setContentView加進來就成了content的直接子View白热。
繪制的流程是這樣、詳情請參考
http://www.reibang.com/p/5a71014e7b1b