</br>
先来考虑一个简单的功能需求:Activity启动时,获取一个文本框的长宽值
你第一反应可能会这样获取:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvTest = (TextView) findViewById(R.id.tv_test);
int height = tvTest.getHeight();
int width = tvTest.getWidth();
Log.e("log", "height=" + height + "; width=" + width);
}
但没有获取到
11-07 19:55:22.377 17988-17988/com.example.david.viewdraw E/log: height=0; width=0
原因是什么呢?
View的初始化分为测量、布局、绘制三个步骤。当View的测量步骤完成后,才能获取到其真实的长宽值。而view的初始化和Activity的启动不是同步执行的,因此无法确保在onCreate、onStart或onResume时,view的测量步骤已经完成。如果没有完成,则只能获取到默认值0。
好在还可以用其他方式获取。
Activity/View#onWindowFocusChanged.
Activity启动后,当执行到onWindowFocusChanged方法时,view的初始化已经完成,因此可以获取到其正确的长宽值。
需要注意的是,onWindowFocusChanged方法在Activity的窗口得到焦点和失去焦点时都会被调用,因此当Activity多次的进行onResume和onPause时,onWindowFocusChanged也会多次调用。
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int height = mTvTest.getHeight();
int width = mTvTest.getWidth();
Log.e("log", "height=" + height + "; width=" + width);
}
}
11-08 08:27:55.927 25368-25368/com.example.david.viewdraw E/log: height=65; width=258 .
view.post(runnable)
view的post方法可以将Runnable投递到消息队列的末尾,而当Looper来调用时,view的初始化已经完成了。
@Override
protected void onStart() {
super.onStart();
mTvTest.post(new Runnable() {
@Override
public void run() {
int height = mTvTest.getHeight();
int width = mTvTest.getWidth();
Log.e("log", "height=" + height + "; width=" + width);
}
});
}