1、View的getWidth()和getMeasuredWidth()有什么区别吗?
A、赋值时机
getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的。
private void setMeasuredDimensionRaw(int measuredWidth, int
measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
getWidth()方法中的值则是通过layout(left,top,right,bottom)方法里的一个setFrame来进行确定left,top,right,bottom 四个顶点位置,既初始化mLeft,mTop,mRight,mBottom这四个值,View的四个顶点一旦确认 那么View在父容器中的位置也就确认了.
public final int getWidth() {
return mRight - mLeft;
}
getMeasuredWidth() 当View绘制流程中的measure流程结束以后有值,获取的是View测量宽度
getWidth() 当View绘制流程中的layout流程结束之后有值,获取的是View的实际高度
正常情况下这两者获取的值都是相同的,除非在onMeasure和onLayout过程之后,在去手动调用measure()这个方法 去改变对应的数值,才可能造成两者值不同.
public class CustomView extends android.support.v7.widget.AppCompatTextView {
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right , bottom );
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
measure(0,0);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int width = getWidth();
int height = getHeight();
Log.e("Charles2", "measuredWidth==" + measuredWidth + "--measuredHeight==" + measuredHeight);
Log.e("Charles2", "width==" + width + "---height==" + height);
}
打印日志如下 :
12-18 15:22:50.878 17332-17332/com.example.administrator.myapplication E/Charles2: measuredWidth==117--measuredHeight==53
12-18 15:22:50.879 17332-17332/com.example.administrator.myapplication E/Charles2: width==275---height==275
2、如何在onCreate中拿到View的宽度和高度?
(1)重写 onWindowFocusChanged,需要注意的是此方法会被调用多次。当Activity的窗口
得到焦点和失去焦点时均会被调用一次,使用会频繁调用(不推荐)
(2))View.post (new Runnable)
通过post可以将一个runnable投递到消息队列中,等待Looper调用次runnable的时候,View也已经初始化好了.
viewById.post(new Runnable() {
@Override
public void run() {
Log.e("Charles2","宽=" + viewById.getWidth() + " --高=="+ viewById.getHeight());
}
});
(3)ViewTreeObserver,比如使用 OnGlobalLayoutListener这个接口, 当View树的状态发生改变或者View树的内部的View的可见性发
生改变。onGlobalLayout方法将被回调,因此可以获取宽度,但是onGlobalLayout会被调用多次.如果使用还必须记得销毁这个监听(不推荐)
ViewTreeObserver viewTreeObserver = viewById.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Log.e("Charles2","宽=" + viewById.getWidth() + " --高=="+ viewById.getHeight());
}
});