Android Studio新手开发第二十六天

目录

视图构建过程(二)

视图的测量方法

1.文本尺寸测量

2.图形尺寸测量

3.布局尺寸测量

视图构建过程(二)

之前介绍过视图的四个构造方法以及用法,这是自定义控件的第一步,接下来要介绍视图的测量方法。

视图的测量方法

自定义控件的第二步是测量尺寸,需要重写onMeasure方法。控件的宽高在xml文件中分别由layout_width属性和layout_height属性规定。它们有3种赋值方式,match_parent、wrap_content与具体的数值。第一种与第三种的值获取比较简单,要么取上级视图的数值,要么取具体数值。比较难的是第二种,它需要知道视图自身的尺寸。Android提供了相关的测量方法,支持在不同情况下测量尺寸。需要测量的实体主要有三种,分别为文本尺寸。图形尺寸以及布局尺寸。

1.文本尺寸测量

文本尺寸分为文本的宽度和高度,需要根据文本的大小分别计算。文本宽度可以使用Paint类的measureText方法测量,示例代码如下。

java 复制代码
        Paint paint = new Paint();
        paint.setTextSize(20);//设置文本的大小,参数单位为sp
        paint.measureText("MeasureText");//设置测量文本,返回值单位为px

文本高度的计算较为复杂,计算高度用到FontMetrics类,该类提供了五个与高度相关的属性,如下表所示。

|---------|-------------|
| 距离属性 | 说明 |
| top | 行的顶部与基线的距离 |
| ascent | 字符的顶部与基线的距离 |
| descent | 字符的底部与基线的距离 |
| bottom | 行的底部与基线的距离 |
| leading | 行间距 |

示例代码如下。

XML 复制代码
<?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">

    <TextView
        android:id="@+id/textView_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textSize="20sp"/>
    <TextView
        android:id="@+id/textView_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

部分Java代码如下。

java 复制代码
public class MeasureTextActivity extends AppCompatActivity {

    @Override
    protected 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方法,按照测量规格进行测量操作等。下面以线性布局为例,示例代码如下。

java 复制代码
    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();
    }
相关推荐
JH30735 小时前
B/S架构、HTTP协议与Web服务器详解
前端·http·架构
yi碗汤园5 小时前
【超详细】C#自定义工具类-StringHelper
开发语言·前端·unity·c#·游戏引擎
sky0Lan5 小时前
一个类似 pytest 的 html 报告
android·html·pytest
怪兽20146 小时前
Handler中有Loop死循环,为什么没有阻塞主线程,原理是什么?
android·面试
Kevin Wang7276 小时前
解除chrome中http无法录音问题,权限
前端·chrome
vipbic6 小时前
使用Cursor开发Strapi5插件bag-strapi-plugin
前端·ai编程·cursor
专注前端30年6 小时前
【JavaScript】reduce 方法的详解与实战
开发语言·前端·javascript
ikoala6 小时前
Node.js 25 正式发布:性能飙升、安全升级、全面向 Web 靠拢!
前端·面试·node.js
陈振wx:zchen20086 小时前
前端-ES6-11
前端·es6