在oncreate()方法中无论利用view.getWidth()或是view.getHeiht()还是view.getMeasuredHeight()或view.getMeasuredWidth()来获取view的宽和高,看似没有问题,但其实它们取得值都是0。
之所以获取的值为0,是因为View的绘制需经过以下三个步骤:
1.测量:onMeasure方法设置显示在屏幕上的宽高
2.布局:onLayout方法设置显示在屏幕上的位置(只有在自定义ViewGroup中才用到)
3.绘制:onDraw方法控制显示在屏幕上的样子(ViewGroup没有这个过程)
上面的步骤是异步进行的,在oncreate()中界面处于不可见状态,内存加载组件还没有绘制出来,所以是无法获取它们的尺寸。
一、使用 View.measure()测量 View(最常用的方法)
手动调用测量方法,测量的宽度和高度可能与视图绘制完成后的真实的宽度和高度不一致。
//制定测量规则 参数表示size + mode intwidth=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
intheight=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
view.measure(intwidth,intheight);//调用measure方法之后就可以获取宽高
view.getMeasuredWidth();// 获取宽度
view.getMeasuredHeight();// 获取高度
二.使用ViewTreeObserver. OnPreDrawListener监听事件
在视图将要绘制时调用该监听事件,会被调用多次,因此获取到视图的宽度和高度后要移除该监听事件。
view.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
view.getViewTreeObserver().removeOnPreDrawListener(this);
view.getWidth();// 获取宽度
view.getHeight();// 获取高度
return true;}
});
三.使用ViewTreeObserver. OnGlobalLayoutListener监听事件
在布局发生改变或者某个视图的可视状态发生改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener(){
@Override
public void onGlobalLayout(){
if(Build.VERSION.SDK_INT>=16 {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}else{
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);}
view.getWidth();// 获取宽度
view.getHeight();// 获取高度}
});
四、使用 View.OnLayoutChangeListener 监听事件
在视图的 layout 改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。
view.addOnLayoutChangeListener(
new View.OnLayoutChangeListener(){
@Override
public void onLayoutChange(View v,int l,int t,intr,int b,intoldL,int oldT,int oldR,int oldB){
view.removeOnLayoutChangeListener(this);
view.getWidth();// 获取宽度
view.getHeight();// 获取高度}
});
五、使用 View.post() 方法(该方法只会执行一次,且逻辑简单,建议使用)
Runnable 对象中的方法会在 View 的measure、layout等事件完成后触发。
UI 事件队列会按顺序处理事件,在 setContentView() 被调用后,事件队列中会包含一个要求重新 layout 的 message,所以任何 post 到队列中的 Runnable 对象都会在 Layout 发生变化后执行。
view.post(newRunnable(){
@Override
public void run(){
view.getWidth();// 获取宽度
view.getHeight();// 获取高度}
});