Android Studio新手开发第二十六天
目录
视图构建过程(二)
视图的测量方法
1.文本尺寸测量
2.图形尺寸测量
3.布局尺寸测量
视图构建过程(二)
之前介绍过视图的四个构造方法以及用法,这是自定义控件的第一步,接下来要介绍视图的测量方法。
视图的测量方法
自定义控件的第二步是测量尺寸,需要重写onMeasure方法。控件的宽高在xml文件中分别由layout_width属性和layout_height属性规定。它们有3种赋值方式,match_parent、wrap_content与具体的数值。第一种与第三种的值获取比较简单,要么取上级视图的数值,要么取具体数值。比较难的是第二种,它需要知道视图自身的尺寸。Android提供了相关的测量方法,支持在不同情况下测量尺寸。需要测量的实体主要有三种,分别为文本尺寸。图形尺寸以及布局尺寸。
1.文本尺寸测量
文本尺寸分为文本的宽度和高度,需要根据文本的大小分别计算。文本宽度可以使用Paint类的measureText方法测量,示例代码如下。
Paint paint = new Paint();paint.setTextSize(20);//设置文本的大小,参数单位为sppaint.measureText("MeasureText");//设置测量文本,返回值单位为px
文本高度的计算较为复杂,计算高度用到FontMetrics类,该类提供了五个与高度相关的属性,如下表所示。
距离属性 | 说明 |
top | 行的顶部与基线的距离 |
ascent | 字符的顶部与基线的距离 |
descent | 字符的底部与基线的距离 |
bottom | 行的底部与基线的距离 |
leading | 行间距 |
示例代码如下。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".CustomWidget.MeasureTextActivity"android:orientation="vertical"><TextViewandroid:id="@+id/textView_1"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/app_name"android:textSize="20sp"/><TextViewandroid:id="@+id/textView_2"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>
部分Java代码如下。
public class MeasureTextActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_measure_text);TextView textView_1, textView_2;textView_1 = findViewById(R.id.textView_1);textView_2 = findViewById(R.id.textView_2);float width = getWidth(textView_1.getText().toString(), textView_1.getTextSize());float height = getHeight(textView_1.getText().toString(), textView_1.getTextSize());String string = String.format("上面文本的大小为%.0fpx,宽度为%.0fpx,高度为%.0fpx", textView_1.getTextSize(), width, height);textView_2.setText(string);}public float getWidth(String text, float textSize) {if (TextUtils.isEmpty(text)) {return 0;}Paint paint = new Paint();paint.setTextSize(textSize);return paint.measureText(text);}public float getHeight(String text, float textSize) {if (TextUtils.isEmpty(text)) {return 0;}Paint paint = new Paint();paint.setTextSize(textSize);paint.measureText(text);Paint.FontMetrics fontMetrics = paint.getFontMetrics();return fontMetrics.descent - fontMetrics.ascent;//返回值单位为px}
}
效果图如下。
2.图形尺寸测量
图形尺寸测量较为简单,因为Android提供了现成的方法获取宽高。如果图形格式为Bitmap则调用getWidth方法或者getHeight方法获取宽高。若是Drawable格式就通过方法getIntrinsicWidth以及方法getIntrinsicHeight获取宽高。
3.布局尺寸测量
布局尺寸测量不同于上述两种尺寸,布局中可能有其他视图或者布局存在,而且还有padding与margin。逐个测量布局的内部控件是不现实的。View类提供了一种测量整体布局的思路,对应layout_width与layout_height的三种赋值方式,Android的视图基类同样提供了三种测量方式,具体说明如下表所示。
测量模式 | 宽高赋值方式 | 说明 |
AT_MOST | MATCH_PARENT | 达到最大 |
UNSPECIFIED | WRAP_CONTENT | 自适应 |
EXACTLY | 具体dp值 | 精确尺寸 |
围绕这三种方式衍生了相关的度量方法,如ViewGroup类的getChildMeasureSpec方法,用于获取下级视图的测量规格、MeasureSpec类的makeMeasureSpec方法,根据指定参数指定测量规格、View类的measure方法,按照测量规格进行测量操作等。下面以线性布局为例,示例代码如下。
public float getLayoutHeight(View view){LinearLayout llayout = (LinearLayout) view;// 获得线性布局的布局参数ViewGroup.LayoutParams params = llayout.getLayoutParams();if (params == null) {params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);}// 获得布局参数里面的宽度规格int wdSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);int htSpec;if (params.height > 0) { // 高度大于0,说明这是明确的dp数值// 按照精确数值的情况计算高度规格htSpec = View.MeasureSpec.makeMeasureSpec(params.height, View.MeasureSpec.EXACTLY);} else { // MATCH_PARENT=-1,WRAP_CONTENT=-2,所以二者都进入该分支// 按照不确定的情况计算高度规则htSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);}llayout.measure(wdSpec, htSpec); // 重新丈量线性布局的宽高// 获得并返回线性布局丈量之后的高度。调用getMeasuredWidth方法可获得宽度return llayout.getMeasuredHeight();}