今天来简单的介绍一下怎么在Activity中拿到View的width和height。有人可能会疑问,这个有什么难的,我们直接可以在Activity生命周期函数里面获取width和height。看似简单,实际上在onCreate、onStart、onResume中均无法获取正确的width和height,这是因为View的measure过程和Activity的生命周期方法不是同步的,因此无法保证Activity执行了onCreate、onStart、onResume时,某个View已经测量完毕,如果View还没有测量完毕的话,那么获得的宽和高就是0.那么有什么方法来正确的获取呢?
1.onWindowFoucusChanged
1 public class MainActivity extends AppCompatActivity { 2 3 private Button mButton = null; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 mButton = (Button) findViewById(R.id.id_button); 11 12 } 13 14 @Override 15 public void onWindowFocusChanged(boolean hasFocus) { 16 super.onWindowFocusChanged(hasFocus); 17 if (hasFocus) { 18 int width = mButton.getMeasuredWidth(); 19 int height = mButton.getMeasuredHeight(); 20 Log.i("main", "width = " + width + " height = " + height); 21 } 22 } 23 }
onWindowFocusChanged这个方法的定义是:View已经初始化完毕了,width和height已经准备好了,这个时候去获取width和height是没有问题的。需要注意的是:onWindowFocusChanged会调用多次,当Activity的窗口得到焦点和失去焦点时均会被调用一次。具体来说,当Activity继续执行和暂停执行时,onWindowFocusChanged均会被调用,如果频繁的进行onResume和onPause,那么onWindowFocusChanged也会被频繁的调用。
2.view.post(Runnable)
1 public class MainActivity extends AppCompatActivity { 2 3 private Button mButton = null; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 mButton = (Button) findViewById(R.id.id_button); 11 mButton.post(new Runnable() { 12 @Override 13 public void run() { 14 int width = mButton.getMeasuredWidth(); 15 int height = mButton.getMeasuredHeight(); 16 Log.i("main", "width = " + width + " height = " + height); 17 } 18 }); 19 } 20 21 }
我们可以通过post方法将一个runnable对象投递到mButton的消息队列的尾部,然后等待Looper调用此runnable的时候,View已经初始化好了。
3.ViewTreeObserver
1 public class MainActivity extends AppCompatActivity { 2 3 private Button mButton = null; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 mButton = (Button) findViewById(R.id.id_button); 11 } 12 13 @Override 14 protected void onStart() { 15 super.onStart(); 16 ViewTreeObserver viewTreeObserver = mButton.getViewTreeObserver(); 17 viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 18 @Override 19 public void onGlobalLayout() { 20 mButton.getViewTreeObserver().removeOnGlobalLayoutListener(this); 21 int width = mButton.getMeasuredWidth(); 22 int height = mButton.getMeasuredHeight(); 23 } 24 }); 25 } 26 }
使用ViewTreeObsrever的众多回调可以完成这个功能,比如使用OnGlobalLayoutListener这个接口,当View树的状态发生改变或者View内部的View的可见性发生改变时,onGlobalLayout方法将被回调,因此这是获取View的width和height一个很好的时机。需要注意的是,伴随着View树的状态改变等等,onGlobalLayout会被调用多次。