自定义控件——视图的构建过程——视图的测量方法

 

 

 

 

 

 

 

 

 

 

对于wrap_content形式的宽高,App需要测量它们的实际长度,需要测量的实体主要有3种:

 

 

(1)文本尺寸测量
文本尺寸分为文本的宽度和高度,需根据文本大小分别计算。

 

(2)图形尺寸测量
如果图形是Bitmap格式,就调用getWidth和getHeight方法;如果图形是Drawable格式,就调用getIntrinsicWidth和getIntrinsicHeight方法。

 

(3)布局尺寸测量
调用measure方法按照测量规格进行测量操

 

 

 

 

 

 

 

 

 

 

===========================================================================================

 

 

 

 

 

 

 

文本尺寸的测量

 

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >

        <TextView
            android:id="@+id/tv_size"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:gravity="center"
            android:text="字体大小:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_size"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/tv_size"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </RelativeLayout>

    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:gravity="center"
        android:text="每逢佳节倍思亲"
        android:textColor="@color/black" />

</LinearLayout>

 

 

 

 

 

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:singleLine="true"
    android:gravity="center"
    android:textSize="17sp"
    android:textColor="#0000ff" />

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

代码:

 

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import com.example.myapplication.util.MeasureUtil;

public class MainActivity extends AppCompatActivity
{
    private TextView tv_desc, tv_text;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        tv_desc = findViewById(R.id.tv_desc);
        tv_text = findViewById(R.id.tv_text);


        initSizeSpinner(); // 初始化文字大小的下拉框
    }

    // 初始化文字大小的下拉框
    private void initSizeSpinner()
    {
        ArrayAdapter<String> sizeAdapter = new ArrayAdapter<String>(this, R.layout.item_select, descArray);

        Spinner sp_size = findViewById(R.id.sp_size);
        sp_size.setPrompt("请选择文字大小");
        sp_size.setAdapter(sizeAdapter);
        sp_size.setOnItemSelectedListener(new SizeSelectedListener());
        sp_size.setSelection(0);

    }

    private String[] descArray = {"12sp", "15sp", "17sp", "20sp", "22sp", "25sp", "27sp", "30sp"};

    private int[] sizeArray = {12, 15, 17, 20, 22, 25, 27, 30};

    class SizeSelectedListener implements AdapterView.OnItemSelectedListener
    {


        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3)
        {

            String text = tv_text.getText().toString();

            int textSize = sizeArray[arg2];

            tv_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);

            // 计算获取指定文本的宽度(其实就是长度)
            int width = (int) MeasureUtil.getTextWidth(text, textSize);

            // 计算获取指定文本的高度
            int height = (int) MeasureUtil.getTextHeight(text, textSize);

            String desc = String.format("下面文字的宽度是%d,高度是%d", width, height);

            tv_desc.setText(desc);
        }

        public void onNothingSelected(AdapterView<?> arg0) {}

    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MeasureUtil
package com.example.myapplication.util;

import android.app.Activity;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.text.TextUtils;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;

public class MeasureUtil 
{

    // 获取指定文本的宽度(其实就是长度)
    public static float getTextWidth(String text, float textSize) 
    {
        if (TextUtils.isEmpty(text)) 
        {
            return 0;
        }
        
        Paint paint = new Paint(); // 创建一个画笔对象
        paint.setTextSize(textSize); // 设置画笔的文本大小
        return paint.measureText(text); // 利用画笔丈量指定文本的宽度
    }

    // 获取指定文本的高度
    public static float getTextHeight(String text, float textSize) 
    {
        Paint paint = new Paint(); // 创建一个画笔对象
        paint.setTextSize(textSize); // 设置画笔的文本大小
        FontMetrics fm = paint.getFontMetrics(); // 获取画笔默认字体的度量衡
        return fm.descent - fm.ascent; // 返回文本自身的高度
        //return fm.bottom - fm.top + fm.leading;  // 返回文本所在行的行高
    }

    // 根据资源编号获得线性布局的实际高度(页面来源)
    public static float getRealHeight(Activity act, int resid) 
    {
        LinearLayout llayout = act.findViewById(resid);
        return getRealHeight(llayout);
    }

    // 根据资源编号获得线性布局的实际高度(视图来源)
    public static float getRealHeight(View parent, int resid)
    {
        LinearLayout llayout = parent.findViewById(resid);
        return getRealHeight(llayout);
    }

    // 计算指定线性布局的实际高度
    public static float getRealHeight(View child) 
    {
        LinearLayout llayout = (LinearLayout) child;
        
        // 获得线性布局的布局参数
        LayoutParams params = llayout.getLayoutParams();
        
        if (params == null) 
        {
            params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        }
        
        // 获得布局参数里面的宽度规格
        int wdSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        
        int htSpec;
        
        if (params.height > 0) { // 高度大于0,说明这是明确的dp数值
            // 按照精确数值的情况计算高度规格
            htSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY);
        } else { // MATCH_PARENT=-1,WRAP_CONTENT=-2,所以二者都进入该分支
            // 按照不确定的情况计算高度规则
            htSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        llayout.measure(wdSpec, htSpec); // 重新丈量线性布局的宽高
        // 获得并返回线性布局丈量之后的高度。调用getMeasuredWidth方法可获得宽度
        return llayout.getMeasuredHeight();
    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <include layout="@layout/drag_drop_header" />

    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:gravity="left"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_header"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#eeeeee"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="15dp"
    android:paddingTop="15dp" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_header" />

    <LinearLayout
        android:id="@+id/ll_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/ic_arrow" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_tips"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="轻轻下拉,刷新精彩..."
                android:textColor="@color/black"
                android:textSize="17sp" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

代码:

 

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.myapplication.util.MeasureUtil;

public class MainActivity extends AppCompatActivity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        LinearLayout ll_header = findViewById(R.id.ll_header);

        TextView tv_desc = findViewById(R.id.tv_desc);

        // 计算获取线性布局的实际高度
        float height = MeasureUtil.getRealHeight(ll_header);

        String desc = String.format("上面下拉刷新头部的高度是%f", height);

        tv_desc.setText(desc);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

MeasureUtil

 

package com.example.myapplication.util;

import android.app.Activity;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.text.TextUtils;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;

public class MeasureUtil
{

    // 获取指定文本的宽度(其实就是长度)
    public static float getTextWidth(String text, float textSize)
    {
        if (TextUtils.isEmpty(text))
        {
            return 0;
        }

        Paint paint = new Paint(); // 创建一个画笔对象
        paint.setTextSize(textSize); // 设置画笔的文本大小
        return paint.measureText(text); // 利用画笔丈量指定文本的宽度
    }

    // 获取指定文本的高度
    public static float getTextHeight(String text, float textSize)
    {
        Paint paint = new Paint(); // 创建一个画笔对象
        paint.setTextSize(textSize); // 设置画笔的文本大小
        FontMetrics fm = paint.getFontMetrics(); // 获取画笔默认字体的度量衡
        return fm.descent - fm.ascent; // 返回文本自身的高度
        //return fm.bottom - fm.top + fm.leading;  // 返回文本所在行的行高
    }

    // 根据资源编号获得线性布局的实际高度(页面来源)
    public static float getRealHeight(Activity act, int resid)
    {
        LinearLayout llayout = act.findViewById(resid);
        return getRealHeight(llayout);
    }

    // 根据资源编号获得线性布局的实际高度(视图来源)
    public static float getRealHeight(View parent, int resid)
    {
        LinearLayout llayout = parent.findViewById(resid);
        return getRealHeight(llayout);
    }

    // 计算指定线性布局的实际高度
    public static float getRealHeight(View child)
    {
        LinearLayout llayout = (LinearLayout) child;

        // 获得线性布局的布局参数
        LayoutParams params = llayout.getLayoutParams();

        if (params == null)
        {
            params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        }

        // 获得布局参数里面的宽度规格
        int wdSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);

        int htSpec;

        if (params.height > 0) { // 高度大于0,说明这是明确的dp数值
            // 按照精确数值的情况计算高度规格
            htSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY);
        } else { // MATCH_PARENT=-1,WRAP_CONTENT=-2,所以二者都进入该分支
            // 按照不确定的情况计算高度规则
            htSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        llayout.measure(wdSpec, htSpec); // 重新丈量线性布局的宽高
        // 获得并返回线性布局丈量之后的高度。调用getMeasuredWidth方法可获得宽度
        return llayout.getMeasuredHeight();
    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-09-03 13:39  小白龙白龙马  阅读(45)  评论(0编辑  收藏  举报