• 自定义控件之onMeasure


    最近一直在接触自定义控件的知识,自己就尝试着写了一个小的demo,算是对自定义知识点进行下总结

    今天先来看下自定义控件需要重写的三个重要方法

    看代码

    package com.example.testcode;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    
    public class DrawView extends View {
    
        public DrawView(Context context) {
            super(context);
            Log.e("123", "drawview_1");
            // TODO Auto-generated constructor stub
        }
    
        public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            Log.e("123", "drawview_3");
            // TODO Auto-generated constructor stub
        }
    
        public DrawView(Context context, AttributeSet attrs) {
            super(context, attrs);
            Log.e("123", "drawview_2");
            // TODO Auto-generated constructor stub
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            Log.e("123", "MeasureSpec.UNSPECIFIED==" + MeasureSpec.UNSPECIFIED);
            Log.e("123", "MeasureSpec.AT_MOST==" + MeasureSpec.AT_MOST);
            Log.e("123", "MeasureSpec.EXACTLY==" + MeasureSpec.EXACTLY);
            Log.e("123", "widthMeasureSpec===" + widthMeasureSpec);
            Log.e("123", "heightMeasureSpec===" + heightMeasureSpec);
            Log.e("123", "widthMode==" + widthMode + " widthSize===" + widthSize);
            Log.e("123", "heightMode==" + heightMode + " heightSize==="
                    + heightSize);
            //这两个方法必须有一个,否则会报错
            //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(75, 75);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                int bottom) {
            // TODO Auto-generated method stub
            Log.e("123", "change===" + changed + " left===" + left + " top==="
                    + top + " right===" + right + " bottom===" + bottom);
            super.onLayout(changed, left, top, right, bottom);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            Log.e("123", "onDraw");
            super.onDraw(canvas);
        }
    }

    xml中使用

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.testcode.MainActivity" >
    
        <com.example.testcode.DrawView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#ff0000" />
    
    </RelativeLayout>

    先看下我们的打印结果

      1 09-28 22:53:26.901: E/123(17442): drawview_2
      2 09-28 22:53:26.959: E/123(17442): MeasureSpec.UNSPECIFIED==0
      3 09-28 22:53:26.959: E/123(17442): MeasureSpec.AT_MOST==-2147483648
      4 09-28 22:53:26.959: E/123(17442): MeasureSpec.EXACTLY==1073741824
      5 09-28 22:53:26.959: E/123(17442): widthMeasureSpec===1073741974
      6 09-28 22:53:26.960: E/123(17442): heightMeasureSpec===-2147482958
      7 09-28 22:53:26.960: E/123(17442): widthMode==1073741824 widthSize===150
      8 09-28 22:53:26.960: E/123(17442): heightMode==-2147483648 heightSize===690
      9 09-28 22:53:26.960: E/123(17442): MeasureSpec.UNSPECIFIED==0
     10 09-28 22:53:26.960: E/123(17442): MeasureSpec.AT_MOST==-2147483648
     11 09-28 22:53:26.961: E/123(17442): MeasureSpec.EXACTLY==1073741824
     12 09-28 22:53:26.961: E/123(17442): widthMeasureSpec===1073741899
     13 09-28 22:53:26.961: E/123(17442): heightMeasureSpec===1073741974
     14 09-28 22:53:26.961: E/123(17442): widthMode==1073741824 widthSize===75
     15 09-28 22:53:26.961: E/123(17442): heightMode==1073741824 heightSize===150
     16 09-28 22:53:27.001: E/123(17442): change===true left===0 top===0 right===75 bottom===75
     17 09-28 22:53:27.030: E/123(17442): MeasureSpec.UNSPECIFIED==0
     18 09-28 22:53:27.031: E/123(17442): MeasureSpec.AT_MOST==-2147483648
     19 09-28 22:53:27.031: E/123(17442): MeasureSpec.EXACTLY==1073741824
     20 09-28 22:53:27.031: E/123(17442): widthMeasureSpec===1073741974
     21 09-28 22:53:27.031: E/123(17442): heightMeasureSpec===-2147482958
     22 09-28 22:53:27.031: E/123(17442): widthMode==1073741824 widthSize===150
     23 09-28 22:53:27.031: E/123(17442): heightMode==-2147483648 heightSize===690
     24 09-28 22:53:27.031: E/123(17442): MeasureSpec.UNSPECIFIED==0
     25 09-28 22:53:27.031: E/123(17442): MeasureSpec.AT_MOST==-2147483648
     26 09-28 22:53:27.031: E/123(17442): MeasureSpec.EXACTLY==1073741824
     27 09-28 22:53:27.032: E/123(17442): widthMeasureSpec===1073741899
     28 09-28 22:53:27.032: E/123(17442): heightMeasureSpec===1073741974
     29 09-28 22:53:27.032: E/123(17442): widthMode==1073741824 widthSize===75
     30 09-28 22:53:27.032: E/123(17442): heightMode==1073741824 heightSize===150
     31 09-28 22:53:27.033: E/123(17442): change===false left===0 top===0 right===75 bottom===75
     32 09-28 22:53:27.045: E/123(17442): onDraw

    从上面的结果我们可以知道xml中控件加载过程

    1.xml中使用的控件,加载的时候,调用的是控件两个参数的方法

    public DrawView(Context context, AttributeSet attrs) {
    }

    一个是上下文,一个是属性

    2.解析来会调用

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    }

    方法,这个方法是用来确定控件的宽高的,这个值是从控件的width、height中读出来的。但是我们发现,这两个值的打印结果很奇怪,甚至还有负数。网上对此的解释是

    onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。

    具体什么我也不清楚,不过,它其实是包含了很多信息在里面的。一个就是,从这个数值,我们可以获得这个控件宽跟高的形式

    使用如下方法

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    这个mode的取值,可以有一下三种

    MeasureSpec.EXACTLY-是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。

    MeasureSpec.AT_MOST 是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行 变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。

    MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。

  • 相关阅读:
    docker私有仓库harbor的安装及使用
    docker 搭建 zipkin
    docker安装redis并以配置文件方式启动
    docker 安装 mysql5.7.25
    什么是反射?可以解决什么问题?
    什么是死锁?如何防止死锁?
    说说TCP和UDP的区别
    什么是XSS攻击?
    怎么更改Visual Studio项目名字
    windows上使用getopt和getopt_long
  • 原文地址:https://www.cnblogs.com/zhangshuli-1989/p/vz_custom_15910151.html
Copyright © 2020-2023  润新知