关于View

学习目标

学习关于View的知识

  1. View的getWidth()和getMeasuredWidth()有什么区别吗?
  2. 如何在onCreate中拿到View的宽度和高度?

View的getWidth()和getMeasuredWidth()有什么区别吗?

View的宽高是由View本身和parent容器共同决定的。

getMeasuredWidth()和getWidth()分别对应View的measure与layout阶段,getMeasuredWidth()(int widthMeasureSpec,int heightMeasureSpec)方法中获得,getWidth()是在onLayout后获得。大部分情况下他们是一样的,也有一些不相同的情况,例如,在父View的onLayout中或者在View本身的onDraw方法中调用measure(0,0)(其中参数0可以自己设置)方法,两者的结果可能会不同。

getWidth()源码:

getWidth

可以看出,getWidth()返回的是右边的坐标减去左边的坐标,这是要在布局以后才能确定的,也就是说要在onLayout后才能得到,所以getWidth()是在View设定好布局后整个View的宽度。

getMeasuredWidth()源码:

getMeasureWidth

可以看出getMeasuredWidth返回的是原始测量宽度,所以getMeasuredWidth是对View内容进行测量后得到View内容占据的宽度。

在fuView的onLayout中或者在View本身的onDraw方法中调用measure(0,0)(其中参数0可以自己设置)方法时,如下:

testActivity

testXml
此时的打印结果为:
testResult

所以可以得出结论:getWidth()是View设定好布局后整个View的宽度,getMeasureWidth()是对View上的内容进行测量后得到的View内容的宽度。

如何在onCreate中拿到View的宽度和高度?

onCreate中获取View的宽高有3中方式

我们先定义一个获取View宽高的方法:

getWH

  • View.post(Runnable runnable)

    利用View的通信机制,发送一个message到Message queue中,当View layout处理完成时,自动发送消息,通知UI线程,取巧的获取View的宽高,代码简洁,使用简单,相对比ViewTreeObserver监听处理,还不需要手动移除观察者监听事件。

runnable
此时打印结果:
runnableResult

  • ViewTreeObserver.addGloblLayoutListener(OnGlobalLayoutListener listener)

    监听View的onLayout绘制过程,一旦layout发生变化,立即回调onLayoutChange方法。
    treeGlobal
    此时打印结果:
    treeGlobalRresult

注意:使用完后要调用removeOnGlobalLayoutListener方法移除监听事件,
避免后续每一次发生全局View变化时都会回调这个事件,影响性能。

  • View.measure(int widthMeasureSpec,int heightMeaseureSpec)

    View.MeasureSpec.makeMeasureSpec(@IntRange(from = 0,to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,@MeasureSpecMode int mode)
    

    其中,MeasureSpec.MODE_SHIFT = 30

    size 的最大值为(1 << 30)-1,即用30位二进制表示,最大为30个1(2^30 - 1);
    measure
    打印结果:
    measureResult
    measure1
    打印结果:
    measure1Result

除了在onCreate中获取View的宽高,还可以在Activity的onWindowFocusChanged(boolean hasFocus)中获取

源码:
focussource
focus
打印结果:
focusResult