Activity获取控件宽高的最佳时机和方法
我们在做android UI方面开发的时候,获取某一个控件宽高是不可避免的事情,获取view的宽高android提供有现成的方法View.getWidth()和View.getHeight(),但是如果获取时机不对,我们获取到的宽高值会为0.那么什么时候调用才能获取到正确的值呢?
我们都知道只有在View的onlayout方法执行完之后,其宽高值才能确定,而在Activity中,有很多生命周期相关的方法onCreate、onStart、onResume,哪个方法是在onLayout之后执行的呢?我们首先会想到onResume方法里面是不是能获取到,我们来测试一下。界面布局如下
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.localuser.retrofittest.Drawable.MyDrawableView
android:layout_width="400dp"
android:layout_height="400dp"
android:id="@+id/drawable_view"
android:background="@android:color/darker_gray"/>
</LinearLayout>
Acitivity的代码如下:
public class DrawableActivity extends AppCompatActivity { public static String TAG_PREX = "DrawableActivity--"; private String TAG = TAG_PREX+getClass().getSimpleName(); private MyDrawableView myDrawableView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { Log.d(TAG,"onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_drawable_main); myDrawableView = findViewById(R.id.drawable_view); } @Override protected void onResume() { super.onResume(); Log.d(TAG,"onResume()"); Log.d(TAG,"myDrawableView.getWidth() = "+myDrawableView.getWidth()+",myDrawableView.getHeight() = "+myDrawableView.getHeight()); } }
为了结合View的绘制流程,我自定义一个ImageView:
public class MyDrawableView extends android.support.v7.widget.AppCompatImageView { private String TAG = DrawableActivity.TAG_PREX+getClass().getSimpleName(); public MyDrawableView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.d(TAG,"onMeasure()"); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.d(TAG,"onLayout()"); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.d(TAG,"onDraw()"); } }
运行日志如下:
从日志可以看出,Activity的resume方法执行完的时候,View的onLayout方法还未执行,在onResume方法是获取不到View的宽高的。那么在onResume之前的生命周期方法更不用提了。那么我们应该怎么获取呢,其实Activity有一个生命周期方法onWindowFocusChanged(),这个方法会在View.onLayout()方法之后执行,我们修改修改一下Activity,运行日志如下:
从日志可以看出,在onWindowFocusChanged()的确可以正确获取到view的宽和高。
另外还有一种方法,就是利用View.post(Runable)方法,用法如下:
myDrawableView.post(new Runnable() { @Override public void run() { Log.d(TAG,"view.post.run"); Log.d(TAG,"myDrawableView.getWidth() = "+myDrawableView.getWidth()+",myDrawableView.getHeight() = "+myDrawableView.getHeight()); } });
post方法可以用在Activity的任何生命周期中,甚至在onCreate中用都可以,运行日志如下: