Android获取View的宽高与View.measure详解
原文地址:http://blog.csdn.net/canot/article/details/50430998
在oncreate()中无论利用view.getWidth()或是view.getHeiht()还是view.getMeasuredHeight或view.getMeasuredWidth()来获取view的宽和高,看似没有问题,其实他们取得值是0,并不是你想要的结果。这是因为每个布局都要经过如下三个步骤:
测量:onMeasure 设置自己显示在屏幕上的宽高
布局:onLayout 设置自己显示在屏幕上的位置(只有在自定义ViewGroup中才用到)
绘制:onDraw 控制显示在屏幕上的样子(viewgroup没有这个过程)
如上的步骤是异步进行的,在oncreate()中界面处于不可见状态,内存加载组件还没有绘制出来,所以是无法获取他的尺寸。
那如何在绘制组件之前能获取到该组件的尺寸大小呢?
方法一(最常用的方法):
//手动调用测量方法。
//制定测量规则 参数表示size + mode
int width =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int height =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
view.measure(width,height);
//调用measure方法之后就可以获取宽高。
int height=view.getMeasuredHeight();
int width=view.getMeasuredWidth();
方法二(设置树桩结构监听器):
ViewTreeObserver vto =view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height =view.getMeasuredHeight();
int width =view.getMeasuredWidth();
}
});
方法三(增加组件绘制之前的监听):
ViewTreeObserver vto =view.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
int height =view.getMeasuredHeight();
int width =view.getMeasuredWidth();
}
});
详解View.measure:
measure()方法是实际测量的方法,而在绘制布局过程中调用的onMeasure()只是制定测量规则.
在自定义布局中我们一般重写onMeasure()方法,measure()方法是final的,子类无法重写。
看到measure函数有2个参数,int widthMeasureSpec 和 int heightMeasureSpec表示具体的测量规则。
这两个数值不是普通的数值, 它表示: size + mode
例如:
int widthMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.EXACTLY);
int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.AT_MOST);
模式分为:
View.MeasureSpec.EXACTLY:表示父视图希望子类的大小是specSize中制定的大小.
View.MeasureSpec.AT_MOST:父试图希望子类的大小最高不超过specSize中制定的大小.
View.MeasureSpec.UNSPECIFIED:父试图不对子类实施任何限制,子试图可以得到自己想得到的任意大小.
需求:
在TextView中通过代码调用setText()动态的设置文本,要求在设置文本之后获取其宽高.
TextView的布局方式为width:match_parent height:wrap_content
int width=textView.getMeasuredWidth(); // 开始宽度 textView.getLayoutParams().height= ViewGroup.LayoutParams.WRAP_CONTENT;// 高度包裹内容 int widthMeasureSpec=View.MeasureSpec.makeMeasureSpec(width,View.MeasureSpec.EXACTLY); //宽度是match_parent.即是View.MeasureSpec.EXACTLY int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.AT_MOST); //让高度最大为1000 textView.measure(widthMeasureSpec, heightMeasureSpec); return des_content.getMeasuredHeight();
这样就获取到Textview的高的,根据文本的多少获取不同高度。之前很多人可能直接measure(0,0)来测量看,其实就是:
int widthMeasureSpec=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
利于这个方法为ImageView设置宽高比例显示:
通过一个自定义布局把ImageView包裹起来:
重写这个自定义布局的onMeasure()方法修改其测量规则,让其款高按一定比例显示:
int ratio = 2.43
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// widthMeasureSpec 宽度的规则 包含了两部分 模式 值
int widthMode = MeasureSpec.getMode(widthMeasureSpec); // 模式
int widthSize = MeasureSpec.getSize(widthMeasureSpec);// 宽度大小
int width = widthSize - getPaddingLeft() - getPaddingRight();// 去掉左右两边的padding
int heightMode = MeasureSpec.getMode(heightMeasureSpec); // 模式 int heightSize = MeasureSpec.getSize(heightMeasureSpec);// 高度大小 int height = heightSize - getPaddingTop() - getPaddingBottom();// 去掉上下两边的padding //如果width是match_parent if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) { // 修正一下 高度的值 让高度=宽度/比例 height = (int) (width / ratio + 0.5f); // 保证4舍五入 } else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) { // 由于高度是精确的值 ,宽度随着高度的变化而变化 width = (int) ((height * ratio) + 0.5f); } // 重新制作了新的规则 widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY, width + getPaddingLeft() + getPaddingRight()); heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY, height + getPaddingTop() + getPaddingBottom()); super.onMeasure(widthMeasureSpec, heightMeasureSpec);}
更多相关文章
- android自定义Adapter
- CardView卡片效果
- Android(安卓)Camera 二 JNI JAVA和C/CPP图像数据传输流程分析
- Android(安卓)官方架构组件(一)——Lifecycle
- Android基于Http协议实现文件上传功能的方法
- 倒计时效果
- SDK is not loaded yet解决方法
- 【Android】原生Progress提示
- EditText焦点自动带出软键盘问题