安卓自定義View詳解

安卓自定義View

知識點:1.ViewRoot和DecorView2.MeasureSpec3.measure layout draw4. 定義View

ViewRoot和DecorView

ViewRootDecorView

ViewRootDecorView

右圖是UI界 的架構圖,每個Activity都包含 個Window對象,Android中通常有PhoneWindow來實現,PhoneWindow將 個DecorView設置爲整個應 窗 的根View.DecorView將要顯示的內容呈現在PhoneWindow

ViewRootDecorView

ViewRoot是連接WindowManagerDecorView的紐帶,View的整個繪製流程的三 步(measurelayoutdraw)都是通過ViewRoot完成的。當Activity對象被創建完畢後,會將DecorView添加到Window中(Window是對窗 的抽象,DecorView是 個窗 的頂級容 View,其本質是 個FrameLayout),同時會創建ViewRootImpl(ViewRoot的實現類)對象,並將ViewRootImplDecorView建 關聯。整個View樹的繪圖流程是在ViewRoot.Java類的performTraversals()函數展開的,該函數做的執 過程可簡單概況爲

根據之前設置的狀態,判斷是否需要重新計算視圖 (measure)、是否重新需要安置視圖的位置(layout)、以及是否需要重繪(draw),其框架過程如下:

整個View樹的繪圖流程是在ViewRoot.Java類的performTraversals()函數展開的,該函數做的執 過程可簡單概況

ViewRootDecorView

下圖是View樹結構,Activity中使 的findViewById(),就是在控件樹中以樹的深度優先遍歷來查找對應的元素.每棵樹的頂部都有 個ViewParent對象,是整棵樹的控制核 ,所有的交互事件都由它統 調度和發配,從 可以對整個視圖進 整體的控制

MeasureSpec

MeasureSpec

是 個32int值,很 程度上決定 個View的尺 規格。受 View的影響。系統會將ViewLayoutParams根據 View施加的規則轉換成對應的MeasureSpec,再根據MeasureSpec來測 出View的寬/ 。

2位代表SpecMode

30位代表SpecSize

UNSPECIGFIED: ViewView有限制,要多 給多 EXACTLY: View已經測出View的需要的精確 ,View最終的 就是SpecSize的值。對應

match_parent和具體數值AT_MOST: View指定 個可 的 SpecSizeView 能 於這個值,對應於wrap_content

MeasureSpec(http://www.alliedjeep.com/119103.htm)下面是MeasureSpec 的工作原理

public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT; public static final int UNSPECIFIED = 0 << MODE_SHIFT; public static final int EXACTLY = 1 << MODE_SHIFT; public static final int AT_MOST = 2 << MODE_SHIFT; public static int makeMeasureSpec(int size, int mode) {

if (sUseBrokenMakeMeasureSpec) { return size + mode;

} else {

return (size & ~MODE_MASK) | (mode & MODE_MASK); }

}
public static int makeSafeMeasureSpec(int size, int mode) {

if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {

return 0; }

return makeMeasureSpec(size, mode); }

public static int getMode(int measureSpec) {

return (measureSpec & MODE_MASK); }

public static int getSize(int measureSpec) {

return (measureSpec & ~MODE_MASK); }

static int adjust(int measureSpec, int delta) { final int mode = getMode(measureSpec);
int size = getSize(measureSpec);
if (mode == UNSPECIFIED) {

// No need to adjust size for UNSPECIFIED mode.

return makeMeasureSpec(size, UNSPECIFIED); }

size += delta; if (size < 0) {

Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + ") spec: " + toString(measureSpec) + " delta: " + delta);

size = 0; }

return makeMeasureSpec(size, mode); }

//... }

MeasureSpec(http://www.alliedjeep.com/119103.htm)普通View

switch (specMode) {
// Parent has imposed an exact size on us case MeasureSpec.EXACTLY:

if (childDimension >= 0) {
resultSize = childDimension; resultMode = MeasureSpec.EXACTLY;

} else if (childDimension ==LayoutParams.MATCH_PARENT) {

// Child wants to be our size. So be it. resultSize = size;
resultMode = MeasureSpec.EXACTLY;

} else if (childDimension ==LayoutParams.WRAP_CONTENT) {

        // Child wants to determine its own size. It

can't be
// bigger than us.

resultSize = size;

resultMode = MeasureSpec.AT_MOST; }

break;

// Parent has imposed a maximum size on us case MeasureSpec.AT_MOST:

if (childDimension >= 0) {
// Child wants a specific size... so be it resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;

} else if (childDimension ==LayoutParams.MATCH_PARENT) {

// Child wants to be our size, but our sizeis not fixed.

// Constrain child to not be bigger than us. resultSize = size;
resultMode = MeasureSpec.AT_MOST;

} else if (childDimension ==LayoutParams.WRAP_CONTENT) {

        // Child wants to determine its own size. It

can't be
// bigger than us.

resultSize = size;

resultMode = MeasureSpec.AT_MOST; }

break;

// Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED:

if (childDimension >= 0) {

        // Child wants a specific size... let him

have it
resultSize = childDimension;

resultMode = MeasureSpec.EXACTLY; } else if (childDimension ==

LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how

big it should // be

resultSize =View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;

resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension ==

LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size....

find out how
// big it should be

resultSize =View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;

resultMode = MeasureSpec.UNSPECIFIED; }

break; }

MeasureSpec(http://www.alliedjeep.com/119103.htm)下 代碼描述 DecorViewMeasureSpec的產 過程

private static int getRootMeasureSpec(int windowSize, int rootDimension) {int measureSpec;

}

switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);break;

case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);break;

default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);break;

}
return measureSpec;

根據它的LayoutParams中的寬 的參數來分,LayoutParams.MATCH_PARENT:其模式爲精確模式, 就是窗 的 LayoutParams.WRAP_CONTENT:其模式爲最 模式, 定,但是 能超過窗 的 固定 ( 如100dp):其模式爲精確模式, 爲<span style="font-siz

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