这是个很初级的问题,解决办法有三个:
- postDelay 延时大法
- 重载View#onSizeChange
- 使用OnGlobalLayoutListener
追究这个原因呢,也没什么太大价值,只是记录一下吧。
那为什么呢?
首先,getWidth返回的是mRight - mLeft,getMeasuredWidth返回的是 mMeasuredWidth & MEASURED_SIZE_MASK。
以mRight为例,是在setRight/Frame方法里被赋值的。源码中的注释说setRight方法是供layout系统调用的,也就是说,会在View的layout过程中被调用;而setFrame就是在layout调用过程中调用的。所以,在layout未被执行前,getWidth一定是0。
onSizeChange
在View#sizeChange方法中,作为hook暴露给了子View。sizeChange方法会在setRight/Top/Bottom/Left/Frame时被调用,而layout时,调用的是setFrame,也就是说在(应该是)第一次onSizeChange的时候,mRight已经被设置了。
OnGlobalLayoutListener
OnGlobalLayoutListener正常情况下是放到了View的mAttachInfo#mTreeObserver中。真正调用mOnGlobalLayoutListeners的是ViewTreeObserver#dispatchOnGlobalLayout。调用dispatchOnGlobalLayout的只有一个地方,那就是ViewRootImpl里那千行大函数performTraversals。回调在performLayout之后,所以这时View的layout已经被执行过了。
其他方法
思路就是看哪些回调在mRight赋值之后了,扫一遍源码,大概还有这几个:
- onLayout
- onDraw
- OnPreDrawListener
跟Draw相关的不一定会在layout后调到,但一旦调到肯定是有getWidth了。