private void getWindowHeight() {
int heightPixels = getResources().getDisplayMetrics().heightPixels;
int height = getWindowManager().getDefaultDisplay().getHeight();
Log.e(TAG, "heightPixels = "+heightPixels);
// output = 1280
Log.e(TAG, "height = "+height );
// output = 1280
}
观察View的绘制流程,设置OnGlobalLayoutListener监听,布局完成时会调用onGlobalLayout(),在onGlobalLayout()方法里面获取空间的宽和高
// 测量树---------
mBtnLocation.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// 控件相对于手机屏幕的位置坐标
// 一个控件在整个屏幕中的坐标位置 --(状态栏48px)
int[] location1 = new int[2];
mBtnLocation.getLocationOnScreen(location1);
Log.e(TAG, "getLocationOnScreen : x = "+location1[0]+" y = "+location1[1] );
// output x = 40 , y = 200
int[] location2 = new int[2];
mBtnLocation.getLocationInWindow(location2);
Log.e(TAG, "getLocationInWindow : x = "+location2[0]+" y = "+location2[1] );
// output x = 40 , y = 200
Rect rect = new Rect();
mBtnLocation.getWindowVisibleDisplayFrame(rect);
Log.e("getWindowVisible","矩形左 = "+rect.left+" 矩形上 = "+rect.top +
" 矩形右 = "+rect.right +" 矩形下 = "+rect.bottom);
// output (0,48,720,1280)
// 移除树构建测量 防止内存泄漏-------
mBtnLocation.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
说明:
OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过getViewTreeObserver()获得。
getWindowVisibleDisplayFrame()执行结果均是指当前Window实际的可视区域大小,此处不包含状态栏高度
getLocationOnScreen getLocationInWindow 得到view在屏幕上的位置,相对屏幕左上角,此处包含了状态栏的偏移了
我们可以比较其bottom,因为都是从屏幕左上角为参照物的
这里提醒一下,如果想拿到控件在屏幕的位置应当在观察树中去获得,假如在onCreate()中去获得,显示的是不当的
private void originLocation() {
// 必须等布局完了之后才能
int[] locations = new int [2];
llLocation.getLocationOnScreen(locations);
Log.e(TAG,"x = "+locations[0] ); // x = 0
Log.e(TAG,"y = "+locations[1] ); // y = 0
}
开发者手动调用测量方法
private void getMeasureTextHeight(){
Log.e(TAG, "measure之前" );
Log.e(TAG, "宽 = "+mBtnLocation.getMeasuredWidth()+",高 = "+mBtnLocation.getMeasuredHeight());
mBtnLocation.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
Log.e(TAG, "measure之后" );
Log.e(TAG, "宽 = "+mBtnLocation.getMeasuredWidth()+",高 = "+mBtnLocation.getMeasuredHeight());
}
06-18 15:08:54.967 11070-11070/com.jit.bgwithasset E/位置: measure之前
06-18 15:08:54.967 11070-11070/com.jit.bgwithasset E/位置: 宽 = 0,高 = 0
06-18 15:08:54.968 11070-11070/com.jit.bgwithasset E/位置: measure之后
06-18 15:08:54.968 11070-11070/com.jit.bgwithasset E/位置: 宽 = 208,高 = 96
这位网友讲的很好,链接
⚠️注意
如果组件的宽度或高度设置为fill_parent或者match_parent。使用getMeasuredHeight 或者 getMeasuredHeight方法获取组件宽度或者高度时,当组件中包含其他子组件时,所获得的实际值是这些组件所占的最小宽度和最小高度。
实验如下
private void getMeasureLinearHeight(){
Log.e(TAG, "measure之前" );
Log.e(TAG, "宽 = "+llLocation.getMeasuredWidth()+",高 = "+llLocation.getMeasuredHeight());
llLocation.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
Log.e(TAG, "measure之后" );
Log.e(TAG, "宽 = "+llLocation.getMeasuredWidth()+",高 = "+llLocation.getMeasuredHeight());
}
发现了没,测量到的是其子布局的大小哦。
06-18 15:23:53.161 12270-12270/com.jit.bgwithasset E/位置: 宽 = 0,高 = 0
06-18 15:23:53.161 12270-12270/com.jit.bgwithasset E/位置: measure之后
06-18 15:23:53.161 12270-12270/com.jit.bgwithasset E/位置: 宽 = 60,高 = 60
小结
当我们使用measure(0,0)的时候,一定要注意大多用于测量view,而不是用于viewGroup布局。假如测量的是VG那么其大小是其子布局所占据的大小。再有如果viewgroup不含有子布局其实是没用的,测量的宽高都是0。
private void getMeasureHeight() {
mBtnLocation.post(new Runnable() {
@Override
public void run() {
Log.e(TAG, "run: "+ mBtnLocation.getMeasuredHeight());
Log.e(TAG, "run: "+mBtnLocation.getMeasuredWidth());
// output width = 208 height = 96
}
});
}
Android 中获取控件宽和高的方法(详细解析)