自定义View之圆形TextView

 

 
 

【1】自定义View的属性 :

  在res/values下新建一个attrs.xml文件,在里面定义我们的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="titleText" format="string"/>
    <attr name="titleTextColor" format="color"/>
    <attr name="backColor" format="color"/>
    <attr name="titleTextSize" format="dimension"/>
<declare-styleable name="CustomCircleView">
    <attr name="titleText"/>
    <attr name="titleTextColor"/>
    <attr name="titleTextSize"/>
    <attr name="backColor"/>
</declare-styleable>
</resources>

在布局定义View,这里定义了5个:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >


    <com.dhl.customview.view.CustomCircleView
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:titleText="123456"
        app:titleTextColor="@color/colorAccent"
        android:padding="5dp"
        android:layout_marginLeft="30dp"
        android:layout_centerInParent="true"
        app:titleTextSize="14sp"
        />
    <com.dhl.customview.view.CustomCircleView
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:titleText="123456"
        app:titleTextColor="@color/colorAccent"
        android:padding="5dp"
        android:layout_marginLeft="30dp"
       android:layout_alignParentRight="true"
        app:titleTextSize="18sp"
        />
    <com.dhl.customview.view.CustomCircleView
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:titleText="123456"
        app:titleTextColor="@color/colorAccent"
        android:padding="5dp"
        android:layout_marginLeft="30dp"
        app:backColor="#abdc25"
        android:layout_alignParentLeft="true"
        app:titleTextSize="18sp"
        />
    <com.dhl.customview.view.CustomCircleView
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:titleText="123456"
        app:titleTextColor="@color/colorAccent"
        android:padding="5dp"
        android:layout_marginLeft="30dp"
       android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        app:titleTextSize="18sp"
        />

    <com.dhl.customview.view.CustomCircleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:titleText="123456"
        app:titleTextColor="@color/colorAccent"
        android:padding="5dp"
        android:layout_marginLeft="30dp"
        app:backColor="#abdc25"
        android:layout_alignParentBottom="true"
       android:layout_alignParentLeft="true"
        app:titleTextSize="18sp"
        />

</RelativeLayout>

【2】在构造方法中获取自定义属性:

public CustomCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a= context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleView,defStyleAttr,0);
        /**
         * 这个获得是你实际在layout中设置的属性个数
         */
        int n = a.getIndexCount();
        for(int i = 0;i<n;i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.CustomCircleView_titleText:
                    titleText = a.getString(attr);
                    break;
                case R.styleable.CustomCircleView_titleTextColor:
                    titleColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.CustomCircleView_backColor:
                    backColor = a.getColor(attr,Color.GREEN);
                    break;
                case R.styleable.CustomCircleView_titleTextSize:
                    titleSize = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();
        mPaint = new Paint();
        mPaint.setTextSize(titleSize);
        mBound = new Rect();
        /**
         * 获得绘制文本的宽和高
         */
        mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);


    }

获取自定义属性,并且遍历每个属性,set相应的值。

【3】重写onMeasure:

  MeasureSpce的mode有三种:EXACTLY, AT_MOST,UNSPECIFIED,EXACTLY顾名思义,有了准确的值,一般是固定的宽高度或者match_parent。AT_MOST表示在一个范围内,一般为wrap_content。UNSPECIFIED表示View能有多大就多大,很少用到。


 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.e(TAG,"onMeasure");
        int width = getMySize(100,widthMeasureSpec);
        int height = getMySize(100,heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

封装计算相应的宽高

/**
     * 计算相应的宽高
     * @param defaultSize 默认值
     * @param measureSpec
     * @return
     */
    private int getMySize(int defaultSize, int measureSpec) {
        int mySize = defaultSize;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
                //我们将自己计算View的大小
                mPaint.setTextSize(titleSize);
                mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
                float textWidth = mBound.width();
                int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
                mySize = desired;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                mySize = size;
                break;
            }
        }
        return mySize;
    }

主要是对 AT_MOST这种情况的处理,这个处理好了,View的宽和高就是对的。

【4】重写onDraw():

    这个主要是把相应View绘制出来,

  

 protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.e(TAG,"onDraw");
        //圆的半径
        int r = Math.min(getMeasuredWidth() / 2,getMeasuredHeight()/2);
        //圆心的横坐标
        int centerX =r;
        //圆心的纵坐标
        int centerY =r;
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        mPaint.setColor(backColor);
        //绘制圆
        canvas.drawCircle(centerX, centerY, r, mPaint);
        mPaint.setColor(titleColor);
        //绘制Text
        canvas.drawText(titleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
    }
一个圆形的TextView就此完成,下面贴出全部代码:

public class CustomCircleView extends View {

    private static final String TAG = CustomCircleView.class.getSimpleName();
    /**
     * 文本
     */
    private String titleText ;
    /**
     * 字体颜色
     */
    private int titleColor =Color.BLACK ;
    /**
     * 背景颜色,设置默认颜色
     */
    private int backColor = Color.GRAY;

    /**
     * 色值
     */
    private int titleSize ;

    /**
     *控制文本的范围
     */
    private Rect mBound;
    private Paint mPaint;

    public CustomCircleView(Context context) {
        this(context, null);
    }

    public CustomCircleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public CustomCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a= context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleView,defStyleAttr,0);
        /**
         * 这个获得是你实际在layout中设置的属性个数
         */
        int n = a.getIndexCount();
        for(int i = 0;i<n;i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.CustomCircleView_titleText:
                    titleText = a.getString(attr);
                    break;
                case R.styleable.CustomCircleView_titleTextColor:
                    titleColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.CustomCircleView_backColor:
                    backColor = a.getColor(attr,Color.GREEN);
                    break;
                case R.styleable.CustomCircleView_titleTextSize:
                    titleSize = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();
        mPaint = new Paint();
        mPaint.setTextSize(titleSize);
        mBound = new Rect();
        /**
         * 获得绘制文本的宽和高
         */
        mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);


    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.e(TAG,"onDraw");
        //圆的半径
        int r = Math.min(getMeasuredWidth() / 2,getMeasuredHeight()/2);
        //圆心的横坐标
        int centerX =r;
        //圆心的纵坐标
        int centerY =r;
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        mPaint.setColor(backColor);
        //绘制圆
        canvas.drawCircle(centerX, centerY, r, mPaint);
        mPaint.setColor(titleColor);
        //绘制Text
        canvas.drawText(titleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.e(TAG,"onMeasure");
        int width = getMySize(100,widthMeasureSpec);
        int height = getMySize(100,heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    /**
     * 计算相应的宽高
     * @param defaultSize 默认值
     * @param measureSpec
     * @return
     */
    private int getMySize(int defaultSize, int measureSpec) {
        int mySize = defaultSize;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
                //我们将自己计算View的大小
                mPaint.setTextSize(titleSize);
                mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
                float textWidth = mBound.width();
                int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
                mySize = desired;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                mySize = size;
                break;
            }
        }
        return mySize;
    }

    public void setTitleText(String str)
    {
        titleText = str ;
        invalidate();
    }

}
OK,下面贴出效果图


如有问题,请留言。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值