首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Android 自定義 ViewGroup 生命週期完整執行順序與 onMeasure/onLayout 實戰技巧

     編輯:Java 綜合教學

Android 自定義 ViewGroup 生命週期完整執行順序與 onMeasure/onLayout 實戰技巧

三種引用方式的生命週期差異

引用方式執行順序關鍵差異
XML 佈局引用構造器 → onFinishInflate() → onMeasure (多次) → onSizeChanged → onLayout → onMeasure/onLayout 循環會執行 onFinishInflate (僅一次),適用 findViewById 初始化子 View
setContentView(new CustomView)構造器 → onMeasure → onSizeChanged → onLayout → ...無 onFinishInflate
new CustomView() 不加入父佈局僅構造器不觸發測量佈局流程

ViewGroup 生命週期表

核心方法職責

  • onFinishInflate():XML 解析完成、子 View 已建立,適合 findViewById、綁定事件
  • onMeasure(int widthSpec, int heightSpec):測量自身與子 View 尺寸,**必須呼叫 setMeasuredDimension(w, h)** 確定自已尺寸
  • onSizeChanged(w, h, oldw, oldh):尺寸發生變化時回調,適合依賴尺寸的初始化
  • onLayout(changed, l, t, r, b):決定子 View 位置,呼叫 child.layout(l, t, r, b)
  • draw/drawChild:繪製背景與子 View,通常不需重寫

onMeasure 實戰模板

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 1. 解析父容器施加的測量規格
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
    // 2. 設置自身測量尺寸 (必須)
    setMeasuredDimension(widthSize, heightSize);
    
    // 3. 測量子 View
    View leftMenu = getChildAt(1);
    MarginLayoutParams lp = (MarginLayoutParams) leftMenu.getLayoutParams();
    
    // 子 View 測量規格構建
    int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, 
        mMinDrawerMargin + lp.leftMargin + lp.rightMargin, lp.width);
    int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
        lp.topMargin + lp.bottomMargin, lp.height);
    leftMenu.measure(drawerWidthSpec, drawerHeightSpec);
    
    View content = getChildAt(0);
    lp = (MarginLayoutParams) content.getLayoutParams();
    int contentWidthSpec = MeasureSpec.makeMeasureSpec(
        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
    int contentHeightSpec = MeasureSpec.makeMeasureSpec(
        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
    content.measure(contentWidthSpec, contentHeightSpec);
}

onLayout 實戰模板

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    View content = getChildAt(0);
    content.layout(l, t, r, b); // 佔滿全螢幕
    
    View menu = getChildAt(1);
    int menuWidth = menu.getMeasuredWidth();
    menu.layout(-menuWidth, t, 0, b); // 初始隱藏在左側
}

getMeasuredWidth() vs getWidth()

方法取得時機數值穩定性
getMeasuredWidth()onMeasure 結束後 (setMeasuredDimension 後)固定不變
getWidth()onLayout 結束後可能因佈局調整而變化

若 onLayout 未修改子 View 尺寸,兩者相等。

參考資源

Android ViewGroup 生命週期深度解析

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved