上一篇文章讲了,如何自定义属性,以及在自定义控件的构造方法中如何获取到我们的自定义属性和设置的参数。由于上一周只有三天的时间,在忙一些项目的问题,上一周没有更新文章,不好意思大家。今天我们就来实战一下,如何利用我们的自定义属性。我们来亲自写一个自定义控件,并且利用我们的自定义属性来控制和显示我们的自定义控件。
第一步:自定义属性
在我们项目的res/value目录下新建attr.xml文件在里面定义我们的属性和声明我们的样式
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomTitleView">
<attr name="titleText" format="string" />
<attr name="titleTextColor" format="color" />
<attr name="titleTextSize" format="dimension" />
</declare-styleable>
</resources>
可以看到我们定义了三个属性,他们分别是字体,字体颜色,和字体大小。format是这些属性的取值类型。取值类型有string、color、dimension、integer、enum、boolean、reference、flag、float、fraction。
第二步:自定义控件
package net.fitrun.mysvg;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by 晁东洋 on 2017/4/10.
*/
public class CustomTitleView extends View {
/**
* 文本
*/
private String mTitleText;
/**
* 文本的颜色
*/
private int mTitleTextColor;
/**
* 文本的大小
*/
private int mTitleTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mBound;
private Paint mPaint;
public CustomTitleView(Context context) {
super(context);
}
public CustomTitleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化画笔
mPaint = new Paint();
mPaint.setTextSize(mTitleTextSize);
mPaint.setAntiAlias(true);
// mPaint.setColor(mTitleTextColor);
/**
* 获得绘制文本的最小的宽和高
* 参数,调用的文本
* 从第几个开始
* 到第几个结束
* 返回边界内的字符串
*
*/
//初始化一个空的矩形,所有的坐标都是0。
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
}
}
第三步:在布局文件中声明我们的自定义View
<net.fitrun.mysvg.CustomTitleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
custom:titleText = "3300"
custom:titleTextSize = "40sp"
custom:titleTextColor = "#FF000000"/>
第四:在View的构造方法中获得我们定义的属性
public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
* 获得我们的自定义属性,返回的是自定义属性的一个数组
* */
TypedArray array = context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomTitleView,defStyleAttr,0);
//返回数组的长度
int num = array.getIndexCount();
for (int i =0; i<num;i++){
//遍历数组得到每一个自定义的属性
int attr = array.getIndex(i);
switch (attr){
case R.styleable.CustomTitleView_titleText:
//设置自定义属性的值
mTitleText = array.getString(attr);
break;
case R.styleable.CustomTitleView_titleTextColor:
//设置设置的颜色,第二个参数为默认的颜色
mTitleTextColor = array.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
//设置字体大小,TypeValue可以把px转换为sp.如果没有定义就默认16sp
mTitleTextSize = array.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
break;
}
}
array.recycle();
//初始化画笔
mPaint = new Paint();
mPaint.setTextSize(mTitleTextSize);
mPaint.setAntiAlias(true);
/**
* 获得绘制文本的最小的宽和高
* 参数,调用的文本
* 从第几个开始
* 到第几个结束
* 返回边界内的字符串
*
*/
//初始化一个空的矩形,所有的坐标都是0。
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
}
第五:绘制我们的文字
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置绘制字体的范围背景颜色
mPaint.setColor(Color.BLUE);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);
mPaint.setColor(mTitleTextColor);
canvas.drawText(mTitleText,getWidth()/2 -mBound.width()/2,getHeight()/2+mBound.height()/2,mPaint);
}
第六:此时的效果图如下
第七:View的测量
7.1下面我们的自定义iew的width和height属性修改为warp_content
可以看到并非是我们所需要的效果,字体的布局撑满了全屏,怎么回事呢,原来我们的系统默认的测量结果是MATCH_PARENT.当我们设置了明确的值,测量的结果就是设置的值,当我们设置为warp_content时,系统测量的值就是match_partent.那么如何达到我们需要的效果呢,就需要重写onMeasure()方法,我们自己来测量。首先重写之前我们介绍一下测量的三种模式:
UNSPECIFIED:未指定测量模式。View大小不确定,想要多大有多大。
EXACTLY: 精确值模式。当控件的width和height设置为具体值或者match_parent时就是这个模式。
AT_MOST:最大值模式。父布局决定子布局大小(例如:父布局width或者height设置一个默认的精确值,子布局设置为wrap_content.此时子布局的最大width或者height就是父布局的width或者height)。使用这种测量模式的View,设置的一定是wrap_content。
7.2:重写onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width =0;
int height =0;
//获取实际的宽的测量模式,和宽度的值
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
//设置宽度的值
switch (specMode){
//明确指定了精确的值,或者设置的是Match_parent
case MeasureSpec.EXACTLY:
width =getPaddingLeft() + getPaddingRight() + specSize;
break;
//由父布局决定字布局的大小,一般设置为WARP_CONTENT
case MeasureSpec.AT_MOST:
width = getPaddingLeft()+ getPaddingRight() + mBound.width();
break;
}
/**
* 设置高度
*/
specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode)
{
case MeasureSpec.EXACTLY:// 明确指定了
height = getPaddingTop() + getPaddingBottom() + specSize;
break;
case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
height = getPaddingTop() + getPaddingBottom() + mBound.height();
break;
}
setMeasuredDimension(width, height);
}
7.3效果如图
自定义View的内容还有很多,我会一直更新我的开发技术心得,如果大家喜欢我的文章笔记。请扫描下面的二维码关注我的微信公众号,支持我。上边会有更全面,更详细的内容。谢谢大家。
扫描关注吧: