View 的三个回调函数

本文详细解析了Android中View的生命周期,重点介绍了onMeasure(), onLayout() 和 onSizeChanged()这三个关键回调函数的工作原理及调用顺序。并通过实际示例展示了不同操作(如添加、删除控件)对这些回调函数的影响。
摘要由CSDN通过智能技术生成

本文主要讲解 View 的三个回调函数
- onMeasure() : 回调该方法进行测量
- onLayout() : 回调该方法确定显示的位置
- onSizeChange() : 组件大小改变时进行回调


主程序

//  By lentitude


package com.example.testfunction;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements  View.OnClickListener {
    private ButtonExample1 button1;
    private Button addButton;
    private Button deleteButton;
    private Button deleteView;
    private TextView textView;
    private LinearLayoutExample1 layoutExample1;
    private LinearLayoutExample2 layoutExample2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        // 获取实例
        button1 = (ButtonExample1)findViewById(R.id.button1);
        textView = (TextView)findViewById(R.id.text_view);
        layoutExample2 = (LinearLayoutExample2)findViewById(R.id.layout2);
        layoutExample1 = (LinearLayoutExample1)findViewById(R.id.layout1);
        addButton = (Button)findViewById(R.id.add_button);
        deleteButton = (Button)findViewById(R.id.delete_button);
        deleteView = (Button)findViewById(R.id.delete_text_view);
        addButton.setOnClickListener(this);
        deleteButton.setOnClickListener(this);
        deleteView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.add_button:
                Button button = new Button(this);
                button.setText("按钮3");
                // 设置长宽
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                layoutExample1.addView(button,params);
                break;
            case R.id.delete_button:
                layoutExample2.removeView(button1);
                break;
            case R.id.delete_text_view:
                layoutExample1.removeView(textView);
                break;
            default:
        }
    }
}

其中,ButtonExample1 ,LinearLayoutExample1 ,LinearLayoutExample2 都是重写的 Button 和 LinearLayout ,只是添加了 log 函数,便于观察函数的调用顺序

打开程序,程序的主界面:

这里写图片描述


logcat 中显示:

05-02 08:06:26.849 18615-18615/com.example.testfunction D/ButtonExample1: onMeasure: 
05-02 08:06:26.850 18615-18615/com.example.testfunction D/ButtonExample2: onMeasure: 
05-02 08:06:26.850 18615-18615/com.example.testfunction D/ButtonExample1: onMeasure: 
05-02 08:06:26.850 18615-18615/com.example.testfunction D/ButtonExample2: onMeasure: 
05-02 08:06:26.851 18615-18615/com.example.testfunction D/LinearLayoutExample2: onMeasure: 
05-02 08:06:26.851 18615-18615/com.example.testfunction D/TextViewExample: onMeasure: 
05-02 08:06:26.851 18615-18615/com.example.testfunction D/LinearLayoutExample1: onMeasure: 
05-02 08:06:26.852 18615-18615/com.example.testfunction D/LinearLayoutExample1: onSizeChanged: 
05-02 08:06:26.856 18615-18615/com.example.testfunction D/LinearLayoutExample2: onSizeChanged: 
05-02 08:06:26.857 18615-18615/com.example.testfunction D/ButtonExample1: onSizeChanged: 
05-02 08:06:26.857 18615-18615/com.example.testfunction D/ButtonExample1: onLayout: 
05-02 08:06:26.857 18615-18615/com.example.testfunction D/ButtonExample2: onSizeChanged: 
05-02 08:06:26.858 18615-18615/com.example.testfunction D/ButtonExample2: onLayout: 
05-02 08:06:26.858 18615-18615/com.example.testfunction D/LinearLayoutExample2: onLayout: 
05-02 08:06:26.858 18615-18615/com.example.testfunction D/TextViewExample: onSizeChanged: 
05-02 08:06:26.859 18615-18615/com.example.testfunction D/TextViewExample: onLayout: 
05-02 08:06:26.859 18615-18615/com.example.testfunction D/LinearLayoutExample1: onLayout: 
05-02 08:06:26.869 18615-18615/com.example.testfunction D/ButtonExample1: onDraw: 
05-02 08:06:26.873 18615-18615/com.example.testfunction D/ButtonExample2: onDraw: 
05-02 08:06:26.874 18615-18615/com.example.testfunction D/TextViewExample: onDraw: 
  1. 控件从内到外的顺序调用 onMeasure() 方法来测量大小,一直到 ViewGroup
  2. 从 ViewGroup 从外到内开始调用 onSizeChange() 方法,因为是第一次打开,所有的控件都会回调这个方法
  3. 同时子控件从内到外调用 onLayout() 方法,指定具体显示的布局位置,以确定ViewGroup的布局位置
  4. 最后顺序调用 onDraw() 方法

用流程图表示:

Created with Raphaël 2.1.0 View View ViewGroup ViewGroup 1. onMeasure() 2. onSizeChange() 2. onLayout() 4. onDraw()

点击删除视图框按钮:

这里写图片描述


logcat 中显示:

05-02 08:47:16.047 18615-18615/com.example.testfunction D/LinearLayoutExample1: onMeasure: 
05-02 08:47:16.047 18615-18615/com.example.testfunction D/LinearLayoutExample1: onLayout: 

因为没有对控件的大小进行干扰,只是改变了布局,所以回调父布局的 onMeasure() 方法重新确定大小,回调 onLayout() 方法重新确定布局


点击删除按钮1:

这里写图片描述


logcat 中显示:

05-02 08:53:36.713 18615-18615/com.example.testfunction D/ButtonExample2: onMeasure: 
05-02 08:53:36.730 18615-18615/com.example.testfunction D/LinearLayoutExample2: onMeasure: 
05-02 08:53:36.731 18615-18615/com.example.testfunction D/LinearLayoutExample1: onMeasure: 
05-02 08:53:36.732 18615-18615/com.example.testfunction D/ButtonExample2: onSizeChanged: 
05-02 08:53:36.734 18615-18615/com.example.testfunction D/ButtonExample2: onLayout: 
05-02 08:53:36.734 18615-18615/com.example.testfunction D/LinearLayoutExample2: onLayout: 
05-02 08:53:36.734 18615-18615/com.example.testfunction D/LinearLayoutExample1: onLayout: 
05-02 08:53:36.735 18615-18615/com.example.testfunction D/ButtonExample2: onDraw: 
05-02 08:53:36.750 18615-18615/com.example.testfunction D/ButtonExample2: onDraw: 

同样是删除一个按钮,对其他控件和 ViewGroup 的影响要多的多,这里的 button1, button2 的按钮布局文件为:

        <com.example.testfunction.ButtonExample1
            android:id="@+id/button1"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="按钮1"/>

        <com.example.testfunction.ButtonExample2
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="按钮2"/>

所以在删除 button1 按钮之后,button2 按钮的大小被改变(相当与 match_parent), 这样 button2 的 onMeasure() ,onSizeChange(), onLayout() 方法都会被调用,则父布局的对应方法也会被调用


  1. 先是 button2 调用 onMeasure() 方法,则父布局 LinearLayoutExample1, LinearLayoutExample2 都顺序调用
  2. 因为 大小被改变,则调用 onSizeChange() 方法
  3. 布局位置被改变,从内到外调用 onLayout() 方法

点击添加按钮3:

这里写图片描述


logcat 中显示:

05-02 09:06:19.107 18615-18615/com.example.testfunction D/LinearLayoutExample1: onMeasure: 
05-02 09:06:19.107 18615-18615/com.example.testfunction D/LinearLayoutExample1: onLayout: 

可以看到这里跟前面删除编辑框的效果是一样的,因为没有对其他控件的大小进行干扰,所以回调父布局的 onMeasure() 方法重新确定大小,回调 onLayout() 方法重新确定布局


总结:

  1. 在打开应用程序的时候,ViewGroup 和 View 都会回调 onSizeChange() 方法
  2. ViewGroup 的大小和布局都是通过子 View 的大小和布局来确定的,所以 onMeasure(), onLayout() 方法都是先遍历子 View 的大小和布局之后,再调用 ViewGroup 的对应方法 - 由内向外
  3. 调用顺序:
Created with Raphaël 2.1.0 onMeasure() 打开应用程序或者 大小发生改变? onSizeChange() onLayout() yes no
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值