原理
控件的加载流程如下: 解析布局 - 绑定窗口 - 测量自身大小 - 计算子控件布局 - 绘制
所以,在onMeasure结束,或onLayout开始的时候,View自身就已经完全解析完成了 此时就可以正确获取控件大小了,很多控件,只有在知道自身大小之后,UI方法才能正确执行
测试代码
public class TTView extends View {
public TTView(Context context) {
super(context);
}
public TTView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
@Override
protected void onFinishInflate() {
Console.info("TTView", "onFinishInflate", getMeasuredWidth());
super.onFinishInflate();
}
@Override
protected void onAttachedToWindow() {
Console.info("TTView", "onAttachedToWindow", getMeasuredWidth());
super.onAttachedToWindow();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Console.info("TTView", "onMeasure", getMeasuredWidth());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Console.info("TTView", "onLayout", getMeasuredWidth());
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
Console.info("TTView", "onDraw", getMeasuredWidth());
super.onDraw(canvas);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
Console.info("TTView", "onVisibilityChanged", getMeasuredWidth());
super.onVisibilityChanged(changedView, visibility);
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
Console.info("TTView", "onFocusChanged", getMeasuredWidth());
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
}
2020-10-27 18:38:56.836 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onFinishInflate, 0]
2020-10-27 18:38:56.875 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onAttachedToWindow, 0]
2020-10-27 18:38:56.875 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onVisibilityChanged, 0]
2020-10-27 18:38:56.880 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onMeasure, 0]
2020-10-27 18:38:56.889 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onMeasure, 563]
2020-10-27 18:38:56.891 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onLayout, 563]
2020-10-27 18:38:56.901 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onDraw, 563]
2020-10-27 18:38:57.004 27117-27117/com.aodun.app.bundle W/com.easing.commons: [TTView, onLayout, 563]
可以看到,onLayout执行时,控件大小就确定了,我们可以以这个方法作为控件加载完毕的标志
应用
如果我们有一些操作,需要等控件加载完毕才执行 可以在onLayout中添加一个回调,通过回调就可以告知外界,自身加载完毕了
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if(layoutCompleteListener != null)
layoutCompleteListener.onLayoutComplete();
super.onLayout(changed, left, top, right, bottom);
}
延伸
采用同样的测试方法,我们可以找到Activity布局完全加载的标志 那就是handler.post(runnable)方法,经常测试我们可以得知,handler.post只有在布局完全加载完成时才会执行 如果我们想等布局加载完成再执行代码,将代码写在runnable中,通过handler发送即可