Android -- 自定义view

好记性不如烂笔头

1、View里面不同的构造方法

View里面有四种不同的构造方法,分别是:

View(Context context)
View(Context context, AttributeSet attrs)
View(Context context, AttributeSet attrs, int defStyleAttr)
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)

那我们都是什么时候用到这些构造方法呢?

  1. View(Context context)是当代码创建视图的时候使用的构造函数,通过参数中的context我们可以访问当前主题、资源等。
    例如在Activity的setContentView中可以使用new View(this)来将自己的控件显示出来。
  2. View(Context context, AttributeSet attrs)用于layout文件实例化,会把XML内的参数通过AttributeSet带入到View内。就是当写在xml中的控件被实例化的时候会调用该方法。可以通过attrs获取属性。
  3. 第三个第四个构造函数可以看Android View 四个构造函数详解

2、重写onMeasure()方法

那我们为啥要重写onMeasure()呢?

    <com.example.lifecircletest.MyView
        android:id="@+id/my_view"
        android:layout_height="100dp"
        android:layout_width="wrap_content"
        android:background="#ff0000"/>

MyView是我们自己继承view的一个类,现在还没有重写onMeasure,此时注意 android:layout_width=“wrap_content” 为wrap_content,就是将大小设置为刚好包裹控件内的内容,运行一下,可以看到。
在这里插入图片描述
高度的100dp倒是没啥问题,但是wrap_content咋变成match_parent呢?去看看View里面的onMeasure()方法吧。

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
   public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

可以看到在getDedaultSize中的AT_MOST情况下没有执行,会继续执行case MeasureSpec.EXACTLY:的内容,返回了specSize的值,那我现在有个疑问了,是谁调用了onMeasure()呢?一般子View的实际宽高是由其父视图和本身决定的,父视图是有义务测量其每一个子View,也就是说子View的measure方法其实是其上层的ViewGroup调用的,详细可以去看measureChild中的getChildMeasureSpec,总结一下就是子View的大小是由其父视图和本身决定的。

下面说一下上文中specMode的三个值是什么意思,我们可以通过MeasureSpec.getMode来获得widthMeasureSpec, heightMeasureSpec中低2位的模式,通过MeasureSpec.getSize获取后30位的值表示大小。模式有三种:

  • MeasureSpec.UNSPECIFIED 是当没有指定大小时使用一个默认的大小
  • MeasureSpec.AT_MOST 最大尺寸,控件的宽高为WRAP_CONTENT,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸
  • MeasureSpec.EXACTLY 精准的尺寸,尺寸的值是多少,那么这个组件的高和宽就是多少。

知道这些后我们就可以重写onMeasure了。如果要实现wrap_content的话需要在onMeasure中进行实现。onMeasure中用setMeasuredDimension来设置大小。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getSize(100,widthMeasureSpec),getSize(100,heightMeasureSpec));	//设置大小的长宽
    }

    private int getSize(int measureSpec, int defaultSize){		//这个方法可以得到一个size或者一个自己设定的默认size
        int mSize = defaultSize;

        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode){
            case MeasureSpec.UNSPECIFIED:
                mSize = defaultSize;
                break;
            case MeasureSpec.AT_MOST:
                mSize = size;
                break;
            case MeasureSpec.EXACTLY:
                mSize = size;
                break;
        }
        return mSize;
    }

3、重写onDraw()

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    paint.setColor(Color.BLUE);
    paint.setAntiAlias(true);
    paint.setTextSize(50);
    canvas.drawText("hi man" , 100, 100 , paint);  //绘制一个文字
}

在这里插入图片描述
利用onDraw中的canvas就可以画画了。还有其他很多drawXXX的方法的。

3、获取自定义的属性

3.1设置属性

我们可以在res/values/创建一个attrs.xml的文件来保存我们的属性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView">
        <attr name="color" format="color"/>
    </declare-styleable>
</resources>

declare-styleable中的name就是我们自定义的view,这里的名字是可以随便取的,但是最好和我们的类名字保持一致,在attr中可以申明一个属性的名字和属性所取的格式
format格式
有如上几种格式,也可以用<attr name="color" format="color||integer"/>来让他有多种格式。设置好属性后就可以在我们的自定义view中来使用了。
首先在布局标签里加入xmlns:hb="http://schemas.android.com/apk/res-auto"
hb这个命名空间是可以自己设置的。
接下来就可以在自定义的view中使用了,hb:color="@color/colorPrimary"

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:hb="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.lifecircletest.MyView
        android:id="@+id/my_view"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:background="@drawable/click"
        hb:color="@color/colorPrimary"/>

</LinearLayout>

3.2取出属性
现在我们有了自己的自定义的属性了,像上面的例子,我们就可以不用android:background来设置我们的背景颜色了,那我们接下来该怎么做呢?
还记得第二个构造方法中有一个AttributeSet attrs的参数吗,我们的属性可以从这里面取出来。

	private int mColor;
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyView);
        mColor = array.getColor(R.styleable.MyView_color,Color.BLUE);   //第二个参数是默认的颜色。就是没设置就用这个颜色。
        array.recycle();    //最后记得recycle它
    }

现在我们的onDraw中的Paint的颜色就可以直接使用上面获取到的mColor了。效果还是和之前一样,但是字体颜色我们可以在xml文件中设置了,如果没设置,就默认是蓝色。

4、onLayout

onlayout的重写在自定义viewGroup可以用到,可以控制child view 的布局。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值