Resumen de conocimientos sobre componentes personalizados de Android

1. Comprensión del método onMeasure

Primero, creamos un nuevo componente MyView

package main.com.taiji.component;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class MyView extends View {

    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Primero probamos el caso donde tanto el ancho como el alto son match_parent

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <main.com.taiji.component.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:background="#ffff00"/>
</LinearLayout>

El efecto es el siguiente: 

A continuación, probamos el ancho y el alto de wrap_content 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <main.com.taiji.component.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="#ffff00"/>
</LinearLayout>

El efecto permanece sin cambios (Figura 2)

A continuación, especificamos el ancho y el alto como valores específicos.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <main.com.taiji.component.MyView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="10dp"
        android:background="#ffff00"/>
</LinearLayout>

El efecto es el siguiente: 

 

Modificamos el método OnMeasure en MyView

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int dp=px2dip(getContext(),widthSize);
        setMeasuredDimension(200,200);
    }

    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

Descubrimos que el ancho y el alto del componente se han modificado (observe los 200 aquí, la unidad es px)

Al mismo tiempo, obtenemos la siguiente información mediante depuración

Entonces podemos inferir: el widthMeasureSpec y heightMeasureSpec en el método onMeasure son el ancho y el alto especificados en layout_width y layout_height en la Vista del componente principal (es necesario convertir)

 

¿Cómo usar OnMeasure correctamente?

Tomemos el valor widthMeasureSpec como ejemplo:

El valor de widthMeasureSpec se compone de 32 bits altos y 16 bits bajos. El valor guardado en los 32 bits altos se llama specMode, que se puede obtener a través de MeasureSpec.getMode () como se muestra en el código; los 16 bits bajos son specSize, que también se puede obtener mediante MeasureSpec.) Obtenga

Tres posibilidades de specMode:

MeasureSpec.EXACTLY: La vista principal espera que el tamaño de la vista secundaria se especifique en specSize. EXACTAMENTE es equivalente a establecer match_parent o un valor específico

MeasureSpec.AT_MOST: el tamaño de la subvista es como máximo el valor especificado en specSize, lo que significa que no se recomienda que el tamaño de la subvista exceda el valor dado en specSize. AT_MOST es equivalente a configurar wrap_content

MeasureSpec.UNSPECIFIED: Podemos especificar el tamaño de la vista a voluntad.

 

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
    }

    public int measureWidth(int measureSpec){
        int result=0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if(specMode==MeasureSpec.EXACTLY){
            result=specSize;
        }else {
            result=300;
            if(specMode==MeasureSpec.AT_MOST){
                result=Math.min(result,specSize);
            }
        }
        return result;
    }

    public int measureHeight(int measureSpec){
        int result=0;
        int specMode=MeasureSpec.getMode(measureSpec);
        int specSize=MeasureSpec.getSize(measureSpec);
        if(specMode==MeasureSpec.EXACTLY){
            result=specSize;
        }else {
            result=300;
            if(specMode==MeasureSpec.AT_MOST){
                result=Math.min(result,specSize);
            }
        }
        return result;
    }

Luego probamos:

android:layout_width="200dp"
android:layout_height="200dp"

android:layout_width="300dp"
android:layout_height="300dp"

android:layout_width="match_parent"
android:layout_height="match_parent"

android:layout_width="400dp"
android:layout_height="400dp"

android:layout_width="wrap_content"
android:layout_height="wrap_content"

Se puede ver que cuando configuramos wrap_content, el ancho y el alto del componente personalizado están limitados a no más de 300px (si la situación original cubrirá la pantalla completa, vea la Figura 2).

Supongo que te gusta

Origin blog.csdn.net/hzkcsdnmm/article/details/112978370
Recomendado
Clasificación