Android自定义控件(二)

上篇文章通过继承view定义了一个圆形控件,在界面上绘制一个圆形,并且根据不同的测量模式设置了不同的大小:自定义控件(一) 。但是我们定义的圆形在界面设计时半径、颜色都已经固定了,本文主要总结如何像原生控件一样,通过在xml文件中设置属性来控制圆形的半径以及颜色,并在圆形中心显示一段文字


首先要定义控件的属性名称,在values文件夹中新建attrs.xml文件,声明属性的名称和类型:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="myView">
        <attr name="Text" format="string"/>
        <attr name="TextColor" format="color"/>
        <attr name="CircleColor" format="color"/>
        <attr name="Radius" format="dimension"/>
        <attr name="TextSize" format="dimension"/>
    </declare-styleable>
</resources>


这里定义了文字、文字颜色、半径、圆形颜色、文字大小等属性, format用来指定属性的类型。

      系统提供了TypedArray数据结构来获取自定义属性值,通过TypedArray对象的getString()、getColor()等方法就可以获得xml中设置的属性值,需要注意的是获取完属性值后需要调用TypedArray的recycle方法来完成资源的回收:

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.myView);
        mCircleText = ta.getString(R.styleable.myView_Text);
        mCircleColor = ta.getColor(R.styleable.myView_CircleColor,0);
        mTextColor = ta.getColor(R.styleable.myView_TextColor,0);
        radius = ta.getDimension(R.styleable.myView_Radius,50);
        mTextSize = ta.getDimension(R.styleable.myView_TextSize,15);
        ta.recycle();

获取到属性之后,通过Paint 的setcolor、setTextSize等函数定义画笔,就可以在屏幕上进行绘制了,我们要实现在圆形绘制一段文字,所以在onDraw中绘制完圆形后,通过调用drawText方法绘制文字,使用这个方法时需要注意参数的含义:

canvas.drawText(text,x,y,paint)


(1)text: 表示要绘制的文字内容

(2)x:表示对齐位置,通过调用paint的setTextAlign(Align align)方法,设置文字的对齐标准,Paint.Align.Center:以中心对齐,Paint.Align.LEFT以左边界对齐,Paint.Align.RIGHT以右边界对齐。

(3)y:表示字符baseline 的位置,这里需要特别注意,y不表示文字中心的高度,而表示文字基线的高度,基线是位于文字下方的,就像在直线上写英文字母一样,那条横线叫做基线。

(2)paint:是绘制的画笔


我们在以圆心位置对齐,绘制文字,所以x以中心对齐,设置宽对齐位置为圆心的位置,若要使文字的中心和圆心重合,需要使文字的基线在圆心下方Text.height()/2的高度才能保证,通过获取问题的外接矩形就可以方便的知道文字的高,从而设置y的大小:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        Rect bounds = new Rect();
        mTextPaint.getTextBounds(mCircleText,0,mCircleText.length(),bounds);
        canvas.drawCircle(width/2,height/2,radius,mPaint);
        canvas.drawText(mCircleText,width/2,height/2+bounds.height()/2,mTextPaint);
    }


这样就可以通过xml设置属性,来改变控件的大小、颜色以及文字,但是在设置前,一定要记得引用第三方空间的名字空间,在布局文件中可以看到:

xmlns:android="http://schemas.android.com/apk/res/android


xmlns即xml namespace,指定命名空间为android,所以在使用系统属性的时候可以使用android:来引用系统的属性,自定义的属性就需要创建自己的命名空间,AS中使用如下代码引入命名空间:

xmlns:custom="http://schemas.android.com/apk/res-auto"


将第三方名字空间取名为custom,然后使用自定义属性:

<my.project.ViewTest.myView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        custom:Text="my circle"
        custom:TextColor="#33ff00"
        custom:Radius="50dp"
        custom:CircleColor="#993300"
        custom:TextSize="20sp"
        />

效果图如下:



myView源码:

public class myView extends View {
    private int mCircleColor;
    private String mCircleText = "defuat";
    private int mTextColor;
    private float mTextSize;
    private TypedArray ta ;
    private float radius = 50;
    private Paint mPaint,mTextPaint;
    public myView(Context context) {
        super(context);

        init(context);
    }

    public myView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        ta = context.obtainStyledAttributes(attrs,R.styleable.myView);
        init(context);
    }

    public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        ta = context.obtainStyledAttributes(attrs,R.styleable.myView);
        init(context);
    }

    private void init(Context context){
        mCircleText = ta.getString(R.styleable.myView_Text);
        mCircleColor = ta.getColor(R.styleable.myView_CircleColor,0);
        mTextColor = ta.getColor(R.styleable.myView_TextColor,0);
        radius = ta.getDimension(R.styleable.myView_Radius,50);
        mTextSize = ta.getDimension(R.styleable.myView_TextSize,15);

        mPaint = new Paint();
        mTextPaint = new Paint();
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setTextSize(mTextSize);
        mPaint.setColor(mCircleColor);
        mTextPaint.setColor(mTextColor);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        Rect bounds = new Rect();
        mTextPaint.getTextBounds(mCircleText,0,mCircleText.length(),bounds);
        canvas.drawCircle(width/2,height/2,radius,mPaint);
        canvas.drawText(mCircleText,width/2,height/2+bounds.height()/2,mTextPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMeasured,heightMeasured;
        widthMeasured = measureWidth(widthMeasureSpec);
        heightMeasured = measureHeight(heightMeasureSpec);
        setMeasuredDimension(widthMeasured,heightMeasured);
    }
    private 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 = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);
            }
        }
        return result;
    }

    private 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 = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);
            }
        }
        return result;
    }


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值