应用场景:测量未被添加、未被渲染view的宽高
例如 在view未被绘制显示的情况下,获取列表中的item view 高度,某TextView在设置文本后它所需宽度。
获取View的宽高度方法有很多,多数是在View绘制出来之后才能获取到的,本章讲的是直接测量 view对象所需要的尺寸。
解决方案:调用view.measure()方法测量它的宽高度
第一步:拿到view对象
第二步:设置宽高属性(必须设置尺寸模式)
备注:必须设置模式 View.MeasureSpec.EXACTLY 或 View.MeasureSpec.AT_MOST
模式未设置正确,会影响测量结果
View.MeasureSpec.EXACTLY 相当于match_parent, View.MeasureSpec.EXACTLY相当于wrap_content
例如设置高度为warp_content,则如下设置高度
//设置textView的高度为wrap_content (-2) ,模式为View.MeasureSpec.AT_MOST
int h = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.AT_MOST);
如果宽度为match_parent, 则需要确认父控件的最大尺寸。下面取的是屏幕宽度
//设置textView的宽度为屏幕宽度,模式为macth_parent (View.MeasureSpec.EXACTLY)
int w = View.MeasureSpec.makeMeasureSpec(ScreenUtils.getScreenWidth(), View.MeasureSpec.EXACTLY);
备注:如果需要测试的view,它的尺寸为match_parent,或者有权重,padding,margin等属性,不能简单确定宽高属性的,可以选择测量它的父控件,然后用该view对象获取测量尺寸,一样是可以拿到测量的宽高值的(可以去学习一下view的测量流程)。
第三步:先调用view.measure(width,heigth)方法,再调用获取测量宽高度方法
tv.measure(w,h);
int measuredWidth = tv.getMeasuredWidth();//测量宽度 1080px
int measuredHeight = tv.getMeasuredHeight();//测量高度 137px
应用场景一:测量TextView设置文本后它所需要高度
代码如下:
final TextView tv = new TextView(this);//new一个TextView对象
String testStr = "H";
String str = getNewStr(testStr, 100);//获取100个"H"的字符串
tv.setText(str);//设置文本
int screenWidth = ScreenUtils.getScreenWidth();
int width = screenWidth / 2;
int wrapContent = ViewGroup.LayoutParams.WRAP_CONTENT;
// int measuredWidth = tv.getMeasuredWidth();//未调用测量方法之前,获取测量宽高均为0
// int measuredHeight = tv.getMeasuredHeight();// == 0
//设置textView的宽度为屏幕宽度,模式为macth_parent (View.MeasureSpec.EXACTLY)
int w = View.MeasureSpec.makeMeasureSpec(ScreenUtils.getScreenWidth(), View.MeasureSpec.EXACTLY);
//设置textView的高度为屏幕wrap_content (-2) ,模式为View.MeasureSpec.AT_MOST
int h = View.MeasureSpec.makeMeasureSpec(wrapContent, View.MeasureSpec.AT_MOST);
//设置textView的layouParams属性
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(screenWidth, wrapContent);
tv.setLayoutParams(layoutParams);
//测量宽高 传入的宽高一定要设置模式,否则就是默认模式
tv.measure(w,h);
int lineCount = tv.getLineCount();//3行
int measuredWidth = tv.getMeasuredWidth();//测量宽度 1080px
int measuredHeight = tv.getMeasuredHeight();//测量高度 137px
String newStr = getNewStr(testStr, 200);//获取200个"H"的字符串
tv.setText(newStr);//获取200个"H"的字符串
tv.measure(w,h);//再次测量
int measuredWidth1 = tv.getMeasuredWidth();//测量宽度 1080px
int measuredHeight1 = tv.getMeasuredHeight();//测量高度 measuredHeight:223px
int lineCount1 = tv.getLineCount();//5行
tv.getText();
备注:TextView在没有父控件时,不能多次(2次及以上)调用textView.setText()方法,否则会引起崩溃。这是因为它没有layoutParams造成的,解决方法就是给其先设置上layoutParams, 直接调用onMeasure()方法,测量并不会影响它实际的尺寸,影响它的实际尺寸是layoutParams属性。
结果 :创建一个TextView,设置它的宽为match_parent,最大尺寸为屏宽1080px,高度为wrap_content,设置文本为100个"H", 测量的宽度为屏宽1080px,高度为137px,三行文本;再次设置文本为200个"H",测量的宽高度为1080*223 ,行数为5行。将该view添加到布局后测量的实际宽高与测量宽高是一致的。
备注:textView如果设置maxLines padding等属性,测量的尺寸也是会生效的。
应用场景二:如下列表,按钮的数据是由后台返回决定的,每个按钮的文案有长有短,各个按钮之间有最小间距,且等长等宽。在获取数据后需要先测量屏幕宽度一行能容下几个按钮,再根据测量结果决定列表的显示。
应用场景三:计算稍复杂item布局的高度和该布局中某view的尺寸。
如下代码,某item布局中textView控件使用了权重,padding、margin、maxLines等参数,需要在设置文本后,测量item的高度和textView的尺寸。
解决方案:测量整个item布局,拿到textView对象获取它的测量尺寸。
//获取布局的View对象
View rootView = LayoutInflater.from(this).inflate(R.layout.item_nice, null, false);
//获取该布局中textView
TextView textView = rootView.findViewById(R.id.expandable_text);
textView.setText(getNewStr("H",100));//设置100个H
int screenWidth = ScreenUtils.getScreenWidth();
int width = screenWidth / 1;
int wrapContent = ViewGroup.LayoutParams.WRAP_CONTENT;
int w = View.MeasureSpec.makeMeasureSpec(ScreenUtils.getScreenWidth(), View.MeasureSpec.EXACTLY);
int h = View.MeasureSpec.makeMeasureSpec(wrapContent, View.MeasureSpec.AT_MOST);
rootView.measure(w,h);//测量根布局
int measuredHeight1 = textView.getMeasuredHeight();//textView获取测量宽高度
int measuredWidth1 = textView.getMeasuredWidth();