前言
在实际开发中,有很多组件需要 根据数据,动态生成,或者 追加 / 减少 子view,由于View布局需要时间,此时想要获取父View的最新宽高值,要么手动测量,要么等待布局完成后再获取;
ps:如果使用View树监听观察方法,只调用一次 也是拿不到父View最新值宽高值的。
private boolean initFlag = false; // 初始化,确保只执行一次
public BaseView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (!initFlag) {
fistInit();
initFlag = true;
}
}
});
}
// 只执行一次的方法
public void fistInit() {}
1、案例:因为View布局间隔时间,导致当前父View宽高 和 布局完成后父View宽高不同
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
LinearLayout testBox2 = (LinearLayout) findViewById(R.id.test_box);
Log.d("TAG", "AAA getMeasuredHeight:" + testBox2.getMeasuredHeight());
for (int i = 0; i < 2; i++) {
TextView textView = new TextView(getContext());
textView.setBackgroundColor(0x14F9230A);
textView.setGravity(Gravity.CENTER);
textView.setText("测试 -- 遍历生成的");
testBox2.addView(textView);
}
Log.d("TAG", "BBB getMeasuredHeight:" + testBox2.getMeasuredHeight());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d("TAG", "CCC getMeasuredHeight:" + testBox2.getMeasuredHeight());
}
}, 1000);
}
2、解决方案
2.1 方式一:通过 通知系统重新测量,获取最新的值。
2.2 方式二:当前组件执行post方法,从主线程 重新获取值,post这种属于等待布局完成后 执行。
ps:方式一,是在View没有布局完成就可以拿到最新的值,获取值的速度最快;方式二,post 是等待View布局完成后 执行;根据业务需求自行选择。
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
LinearLayout testBox2 = (LinearLayout) findViewById(R.id.test_box);
Log.d("TAG", "AAA getMeasuredHeight:" + testBox2.getMeasuredHeight());
for (int i = 0; i < 2; i++) {
TextView textView = new TextView(getContext());
textView.setBackgroundColor(0x14F9230A);
textView.setGravity(Gravity.CENTER);
textView.setText("测试 -- 遍历生成的");
testBox2.addView(textView);
}
Log.d("TAG", "BBB getMeasuredHeight:" + testBox2.getMeasuredHeight());
// 方式一:通过 通知系统重新测量,获取最新的值
testBox2.measure(0, 0);
Log.d("TAG", "CCC getMeasuredHeight:" + testBox2.getMeasuredHeight());
// 方式二:当前组件执行post方法,从主线程 重新获取值,post这种属于等待布局完成后 执行
testBox2.post(new Runnable() {
@Override
public void run() {
Log.d("TAG", "DDD getMeasuredHeight:" + testBox2.getMeasuredHeight());
}
});
// 或者 从根视图也可以
// getRootView().post(new Runnable() {
// @Override
// public void run() {
// Log.d("TAG", "DDD getMeasuredHeight:" + testBox2.getMeasuredHeight());
// }
// });
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d("TAG", "EEE getMeasuredHeight:" + testBox2.getMeasuredHeight());
}
}, 1000);
}