用事实说话 View 中常用方法onDraw()、onMeasure()、onLayout()执行顺序

1. 自定义View常用方法执行顺序

1.创建MyView继承View
public class MyView extends View {

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.d("MyView", "MyView(2): ");
    }

    @Override
    protected void onFinishInflate() {
        Log.d("MyView", "onFinishInflate: ");
        super.onFinishInflate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("MyView", "onMeasure: ");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.d("MyView", "onDraw: ");
        super.onDraw(canvas);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        Log.d("MyView", "dispatchDraw: ");
        super.dispatchDraw(canvas);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        Log.d("MyView", "onLayout: ");
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.d("MyView", "onSizeChanged: ");
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onAttachedToWindow() {
        Log.d("MyView", "onAttachedToWindow: ");
        super.onAttachedToWindow();
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        Log.d("MyView", "onWindowFocusChanged: ");
        super.onWindowFocusChanged(hasWindowFocus);
    }
}

2.xml文件中使用
<com.wgheng.test.MyView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp">
</com.wgheng.test.MyViewGroup>
3.Log输出情况
 06-30 08:19:44.487 11310-11310/com.wgheng.text D/MyView: MyView(2): 
 06-30 08:19:44.487 11310-11310/com.wgheng.text D/MyView: onFinishInflate: 
 06-30 08:19:44.540 11310-11310/com.wgheng.text D/MyView: onAttachedToWindow: 
 06-30 08:19:44.553 11310-11310/com.wgheng.text D/MyView: onMeasure: 
 06-30 08:19:44.673 11310-11310/com.wgheng.text D/MyView: onMeasure: 
 06-30 08:19:44.673 11310-11310/com.wgheng.text D/MyView: onSizeChanged: 
 06-30 08:19:44.673 11310-11310/com.wgheng.text D/MyView: onLayout: 
 06-30 08:19:44.704 11310-11310/com.wgheng.text D/MyView: onWindowFocusChanged: 
 06-30 08:19:44.706 11310-11310/com.wgheng.text D/MyView: onMeasure: 
 06-30 08:19:44.706 11310-11310/com.wgheng.text D/MyView: onLayout: 
 06-30 08:19:44.707 11310-11310/com.wgheng.text D/MyView: onDraw: 
 06-30 08:19:44.707 11310-11310/com.wgheng.text D/MyView: dispatchDraw:

从日志中可以看到onWindowFocusChanged()执行时View已经完成了初步的Layout。

Activity生命周期执行的过程中获得或失去焦点时会回调同名的方法,在此同名方法中又回调了View的onWindowFocusChanged()方法,因此比较适合在Activity的onWindowFocusChanged()方法中获取视图的宽和高。

如果在Activity其他方法中获取View的宽和高,很有可能View还未初始化完毕,获得的值为0。

2. 自定义ViewGroup常用方法执行顺序

1.自定义MyViewGroup继承ViewGroup(简单起见继承LinearLayout测试)
public class MyViewGroup extends LinearLayout {

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.d("MyViewGroup", "MyViewGroup(2): ");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("MyViewGroup", "onMeasure: ");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d("MyViewGroup", "onLayout: ");
        super.onLayout(changed, l, t, r, b);
    }

     @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.d("MyViewGroup", "onSizeChanged: ");
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.d("MyViewGroup", "onDraw: ");
        super.onDraw(canvas);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        Log.d("MyViewGroup", "dispatchDraw: ");
        super.dispatchDraw(canvas);

    }

    @Override
    protected void onFinishInflate() {
        Log.d("MyViewGroup", "onFinishInflate: ");
        super.onFinishInflate();
    }

    @Override
    protected void onAttachedToWindow() {
        Log.d("MyViewGroup", "onAttachedToWindow: ");
        super.onAttachedToWindow();
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        Log.d("MyViewGroup", "onWindowFocusChanged: ");
        super.onWindowFocusChanged(hasWindowFocus);
    }
}

2.xml文件中使用

1> 未设置背景

<com.wgheng.test.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp">

</com.wgheng.test.MyViewGroup>

1> 设置背景

<com.wgheng.test.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="#000000">

</com.wgheng.test.MyViewGroup>

3.Log输出情况

1> 未设置背景输出情况

06-30 08:20:52.594 12349-12349/com.wgheng.text D/MyViewGroup: MyViewGroup(2): 
06-30 08:20:52.594 12349-12349/com.wgheng.text D/MyViewGroup: onFinishInflate: 
06-30 08:20:52.639 12349-12349/com.wgheng.text D/MyViewGroup: onAttachedToWindow: 
06-30 08:20:52.644 12349-12349/com.wgheng.text D/MyViewGroup: onMeasure: 
06-30 08:20:52.736 12349-12349/com.wgheng.text D/MyViewGroup: onMeasure: 
06-30 08:20:52.736 12349-12349/com.wgheng.text D/MyViewGroup: onSizeChanged: 
06-30 08:20:52.738 12349-12349/com.wgheng.text D/MyViewGroup: onLayout: 
06-30 08:20:52.763 12349-12349/com.wgheng.text D/MyViewGroup: onWindowFocusChanged: 
06-30 08:20:52.765 12349-12349/com.wgheng.text D/MyViewGroup: onMeasure: 
06-30 08:20:52.765 12349-12349/com.wgheng.text D/MyViewGroup: onLayout: 
06-30 08:20:52.766 12349-12349/com.wgheng.text D/MyViewGroup: dispatchDraw: 

2> 设置背景输出情况

06-30 08:30:51.470 21347-21347/com.wgheng.test D/MyViewGroup: MyViewGroup(2): 
06-30 08:30:51.470 21347-21347/com.wgheng.test D/MyViewGroup: onFinishInflate: 
06-30 08:30:51.541 21347-21347/com.wgheng.test D/MyViewGroup: onAttachedToWindow: 
06-30 08:30:51.557 21347-21347/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 08:30:51.675 21347-21347/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 08:30:51.675 21347-21347/com.wgheng.test D/MyViewGroup: onSizeChanged: 
06-30 08:30:51.675 21347-21347/com.wgheng.test D/MyViewGroup: onLayout: 
06-30 08:30:51.776 21347-21347/com.wgheng.test D/MyViewGroup: onWindowFocusChanged: 
06-30 08:30:51.779 21347-21347/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 08:30:51.779 21347-21347/com.wgheng.test D/MyViewGroup: onLayout: 
06-30 08:30:51.779 21347-21347/com.wgheng.test D/MyViewGroup: onDraw: //绘制背景时回调了onDraw()
06-30 08:30:51.779 21347-21347/com.wgheng.test D/MyViewGroup: dispatchDraw: 

Log中可以看到ViewGroup方法执行顺序和View唯一的差别在于,当ViewGroup绘制背景时会调用onDraw()方法,不绘制背景时就跳过onDraw()方法,执行dispatchDraw()方法

3. ViewGroup嵌套View时方法的执行顺序

1.xml文件中使用
<com.wgheng.test.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="#000000">

    <com.wgheng.test.MyView
        android:layout_width="100dp"
        android:layout_height="100dp" />

</com.wgheng.test.MyViewGroup>

2.Log输出情况
06-30 10:20:16.872 8869-8869/com.wgheng.test D/MyViewGroup: MyViewGroup(2): 
06-30 10:20:16.888 8869-8869/com.wgheng.test D/MyView: MyView(2): 
06-30 10:20:16.890 8869-8869/com.wgheng.test D/MyView: onFinishInflate: 
06-30 10:20:16.890 8869-8869/com.wgheng.test D/MyViewGroup: onFinishInflate: 
06-30 10:20:16.973 8869-8869/com.wgheng.test D/MyViewGroup: onAttachedToWindow: 
06-30 10:20:16.973 8869-8869/com.wgheng.test D/MyView: onAttachedToWindow: 
06-30 10:20:16.976 8869-8869/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 10:20:16.976 8869-8869/com.wgheng.test D/MyView: onMeasure: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyView: onMeasure: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyViewGroup: onSizeChanged: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyViewGroup: onLayout: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyView: onSizeChanged: 
06-30 10:20:17.078 8869-8869/com.wgheng.test D/MyView: onLayout: 
06-30 10:20:17.103 8869-8869/com.wgheng.test D/MyViewGroup: onWindowFocusChanged: 
06-30 10:20:17.103 8869-8869/com.wgheng.test D/MyView: onWindowFocusChanged: 
06-30 10:20:17.107 8869-8869/com.wgheng.test D/MyViewGroup: onMeasure: 
06-30 10:20:17.107 8869-8869/com.wgheng.test D/MyView: onMeasure: 
06-30 10:20:17.107 8869-8869/com.wgheng.test D/MyViewGroup: onLayout: 
06-30 10:20:17.107 8869-8869/com.wgheng.test D/MyView: onLayout: 
06-30 10:20:17.108 8869-8869/com.wgheng.test D/MyViewGroup: onDraw:  //仅当ViewGroup绘制背景时才执行
06-30 10:20:17.108 8869-8869/com.wgheng.test D/MyViewGroup: dispatchDraw: 
06-30 10:20:17.108 8869-8869/com.wgheng.test D/MyView: onDraw: 
06-30 10:20:17.108 8869-8869/com.wgheng.test D/MyView: dispatchDraw: 

这个…看起来略乱,哈哈,就不总结了!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值