1、前言
最近发现自己好像并不是很会自定义View这一块捏,像个癌症晚期患者上不去,下不来,就卡那儿了,所以特发此篇文章学习和分享一下自定义View😅。
2、概述
我将自定义View分为三个步骤:
- 自定义View属性以及获取
- 重写View的onDraw方法
- 重写View的onMeasure方法
本篇将说明自定义View属性以及获取
3、自定义View属性以及获取
自定义View属性
首先在选中项目目录中的values文件夹并新建attrs资源文件。如下图:
Ok,创建完成后我们会看到这样的内容:
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
之后就需要我们在里面申明我们需要的自定义属性了。 属性的申明格式如下:
<attr name="xxxx" format="xxxx"/>
-
name:就是你想要申明属性的名字,到时候获取对应属性依靠的就是这个name。
-
format:申明属性的格式,表示你这个属性它具体是什么,像颜色、字符串或者是其他的类型,但是这个format并不是随意给值的,一下是format的具体可取值的范围:
format format类型 color 表示颜色 string 表示字符串 boolean 表示布尔值 reference 表示引用(如drawable dimension 表示尺寸 float 表示浮点类型 integer 表示整形 fraction 表示百分数 enum 表示枚举 flags 表示位运算
申明属性的方法有多种,这里给出最常用的两种方法:
-
普通写法
<!--背景颜色--> <attr name="solid_color" format="color"/> <!--文字--> <attr name="text" format="string"/> <!--文字颜色--> <attr name="text_color" format="color"/> <!--文字大小--> <attr name="text_size" format="dimension"/>
-
declare-styleable 标签封装 attr
<declare-styleable name="MyCustomView"> <!--背景颜色--> <attr name="solid_color" format="color"/> <!--文字--> <attr name="text" format="string"/> <!--文字颜色--> <attr name="text_color" format="color"/> <!--文字大小--> <attr name="text_size" format="dimension"/> </declare-styleable>
完成之后,我们去创建一个自定义的View,本文类名为MyCustomView继承View,之后补全构造方法即可。
获取自定义属性
首先根据第一步中我们创建的属性在MyCustomView中创建对应的对象:
private int mSolidColor; //背景颜色
private String mText; //文字
private int mTextColor; //文字颜色
private float mTextSize; //文字大小
private Paint mPaint; //画笔
private Rect mTextBound; //接受文字边界
然后写一个获取自定义属性的方法给构造方法调用:
private void obtainAttrs(Context context, AttributeSet attrs) {
}
接着就是最重要的步骤——使用创建TypedArray对象并用其获取到我们创建的属性然后应用到画笔中:
-
普通写法获取属性:
int[] attrsKey = new int[]{R.attr.solid_color, R.attr.text, R.attr.text_color, R.attr.text_size}; TypedArray a = context.obtainStyledAttributes(attrs, attrsKey); mSolidColor = a.getColor(0, 0xFF000000); mText = a.getString(1); mTextColor = a.getColor(2, 0xFFFFFFFF); mTextSize = a.getDimension(3, 14F); a.recycle();
其中attrsKey代表自定义属性的集合,在context的obtainStyledAttributes方法中依靠这个集合的索引来获取具体的属性
-
带有declare-styleable标签获取属性:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); mSolidColor = a.getColor(R.styleable.MyCustomView_solid_color, 0); mText = a.getString(R.styleable.MyCustomView_text); mTextColor = a.getColor(R.styleable.MyCustomView_text_color,0xFFFFFFFF); mTextSize = a.getDimension(R.styleable.MyCustomView_text_size,sp2px(14)); a.recycle();
其中MyCustomView是自定义属性中你申明的标签名字,在后续获取具体的属性时传入的参数格式就为“申明的styleable名称_自定义属性名“ 应用到画笔中:
mPaint = new Paint();
mPaint.setTextSize(mTextSize); //设置文字大小
mTextBound = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);//测量文字边界
获取到TypedArray对象之后就可以使用它的方法来获取对应的属性,这些方法一般都需要索引(index以及一个默认值,最后最重要的一点就是在用完TypedArray对象之后一定一定要记得回收:
a.recycle();//回收
最后重写onDraw,画一个简单的带背景的文字图形:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(mSolidColor);//背景颜色
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);//绘制背景
mPaint.setColor(mTextColor);//文字颜色
canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2, getHeight() / 2 + mTextBound.height() / 2, mPaint);//绘制文字
}
在布局文件引入我们的自定义View:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="@color/white"
tools:context=".MainActivity">
<com.my.mycustomview.MyCustomView
android:layout_width="200dp"
android:layout_height="200dp"
app:solid_color="@color/black"
app:text="AAA"
app:text_color="@color/white"
app:text_size="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果图如下:
4、更多
复用自定义属性
当我们一个自定义View有许多继承的子类,这些字类有共用的属性时可以选择复用自定义属性(以本文中的MyCustomView举例:
<!--背景颜色-->
<attr name="solid_color" format="color"/>
<!--文字-->
<attr name="text" format="string"/>
<!--文字颜色-->
<attr name="text_color" format="color"/>
<!--文字大小-->
<attr name="text_size" format="dimension"/>
<declare-styleable name="MyCustomView">
<attr name="solid_color"/>
<attr name="text"/>
<attr name="text_color"/>
<attr name="text_size"/>
</declare-styleable>
<!--另一个View-->
<declare-styleable name="XXXView">
<attr name="solid_color"/>
<attr name="text"/>
<attr name="text_color"/>
<attr name="text_size"/>
<!--特有属性-->
<attr name="xxxx" format="xxxx"/>
</declare-styleable>
这样共用的属性不用重复定义,在取值的时候只需要改变你申明的styleable名字即可:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.XXXView);
关于attrs
以第3点中的attrs为例子,attr 标签属性会在R类下的attr类中生成16进制地址静态常量:
而使用declare-styleable封装的attr会在R类下的styleable类封装attr类下的16进制地址生成int[]数组,并生成下标索引:
结尾
那么到这里这篇内容就结束了,在这篇文章中讲述了自定义View的基本步骤,以及如何自定义属性和如何获取这些属性,关于重写onDraw方法会放到下一章节说明,时间不定,作者懒狗一条🐶,拜拜👋捏!