Android 自定义View之自定义属性

一:前言

1.什么是命名空间呢
android的命名空间和自定义命名空间

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:前缀
android:名称,能够自定义
url:代表的就是空间,是个没有用的url,是对立资源标识符,绝对于一个常量
2.配置文件attrs.xml
在res下的values文件加下创立一个attrs.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="CustomNumAnimView">        <attr name="round_radius" format="dimension" />        <attr name="round_color" format="color" />        <attr name="text_color" format="color" />        <attr name="text_size" format="dimension" />    </declare-styleable></resources>//格局解析declare-styleablename:属性汇合名称attrname:属性名称format:格局共有11种格局        1.reference(资源id)    <ImageView android:background = "@drawable/图片ID"/>    2.color    <TextView android:textColor = "#00FF00" />    3.boolean    4.dimension(尺寸)(dp)    5.float(浮点值)    6.integer(整形值)    7.string(字符串)    8.fraction(百分比)    9.enum(枚举值)    <declare-styleable name="名称">          <attr name="orientation">      <enum name="horizontal" value="0" />      <enum name="vertical" value="1" />       </attr>    </declare-styleable>    10.flag(位或运算)    留神:位运算类型的属性在应用的过程中能够应用多个值    11.混合属性(应用|离开多个属性)

3.获取属性值

  public CustomNumAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取自定义属性        TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.CustomNumAnimView,defStyleAttr,0);     int roundColor=array.getColor(R.styleable.CustomNumAnimView_round_color, ContextCompat.getColor(context,R.color.purple_200));    float roundRadius=array.getDimension(R.styleable.CustomNumAnimView_round_radius,50);     int  textColor=array.getColor(R.styleable.CustomNumAnimView_text_color, Color.WHITE);    float  textSize=array.getDimension(R.styleable.CustomNumAnimView_text_size,30);        array.recycle();    }

二:自定义View应用自定义属性

public class CustomNumAnimView extends View {    private int roundColor;    //圆的色彩    private int textColor;    //数字的色彩    private float textSize;    //数字字体大小    private float roundRadius;    //圆的半径    private Paint mPaint;     //画笔    private Rect textRect;    //包裹数字的矩形    private boolean isFirstInit = false;   //是否是第一次初始化    private CustomPoint leftPoint;    //右边的数字的实时点    private String leftNum = "9";    private ValueAnimator leftAnim;   //右边数字动画    private boolean isLeftNumInvalidate = false;  //右边数字是否重绘界面    private CustomPoint middlePoint;   //两头的数字的实时点    private String middleNum = "9";    private ValueAnimator middleAnim;   //两头数字动画    private boolean isMiddleNumInvalidate = false;    //两头数字是否重绘界面    private CustomPoint rightPoint;    //左边的数字的实时点    private String rightNum = "9";    private ValueAnimator rightAnim;   //左边数字动画    private boolean isRightNumInvalidate = false;    //左边数字是否重绘界面    public CustomNumAnimView(Context context) {        this(context, null);    }    public CustomNumAnimView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomNumAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取自定义属性        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomNumAnimView, defStyleAttr, 0);        roundColor = array.getColor(R.styleable.CustomNumAnimView_round_color, ContextCompat.getColor(context, R.color.purple_200));        roundRadius = array.getDimension(R.styleable.CustomNumAnimView_round_radius, 50);        textColor = array.getColor(R.styleable.CustomNumAnimView_text_color, Color.WHITE);        textSize = array.getDimension(R.styleable.CustomNumAnimView_text_size, 30);        array.recycle();        //创立画笔        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿标记        mPaint.setTextSize(textSize);//画笔设置文本大小        textRect = new Rect();        //失去数字矩形的宽高,以用来画数字的时候纠正数字的地位        mPaint.getTextBounds(middleNum, 0, middleNum.length(), textRect);    }    /**     * 测量     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int size;        int mode;        int width;        int height;        size = MeasureSpec.getSize(widthMeasureSpec);        mode = MeasureSpec.getMode(widthMeasureSpec);        if (mode == MeasureSpec.EXACTLY) {    //确定的值或者MATCH_PARENT            width = size;        } else {    //示意WARP_CONTENT            width = (int) (2 * roundRadius);        }        mode = MeasureSpec.getMode(heightMeasureSpec);        size = MeasureSpec.getSize(heightMeasureSpec);        if (mode == MeasureSpec.EXACTLY) {    //确定的值或者MATCH_PARENT            height = size;        } else {    //示意WARP_CONTENT            height = (int) (2 * roundRadius);        }        setMeasuredDimension(width, height);    }    /**     * 重写onDraw办法     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (!isFirstInit) {            //是            //初始化三串数字            leftPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 - roundRadius / 2, (float) (getMeasuredHeight() / 2 - roundRadius * (Math.sqrt(3) / 2) - textRect.height() / 2));            middlePoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2, getMeasuredHeight() / 2 - roundRadius - textRect.height() / 2);            rightPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 + roundRadius / 2, (float) (getMeasuredHeight() / 2 - roundRadius * (Math.sqrt(3) / 2) - textRect.height() / 2));            drawText(canvas);            startAnimation();   //开始动画            isFirstInit = true;        } else {            drawText(canvas);        }    }    private boolean isAnimStart(ValueAnimator anim) {        return !anim.isStarted();    }    public void startAnim() {        if (isAnimStart(leftAnim)) {            leftAnim.start();        }        if (isAnimStart(middleAnim)) {            middleAnim.start();        }        if (isAnimStart(rightAnim)) {            rightAnim.start();        }    }    /**     * 在onDestroy办法中调用     */    public void stopAnim() {        leftAnim.end();        middleAnim.end();        rightAnim.end();        leftAnim = null;        middleAnim = null;        rightAnim = null;    }    /**     * 画数字     */    private void drawText(Canvas canvas) {        //画圆        mPaint.setAntiAlias(true);        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);        mPaint.setColor(roundColor);        canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, roundRadius, mPaint);        //写数字        mPaint.setColor(textColor);        mPaint.setTextSize(textSize);        if (isLeftNumInvalidate) {            canvas.drawText(leftNum, leftPoint.getX(), leftPoint.getY(), mPaint);            isLeftNumInvalidate = false;        }        if (isMiddleNumInvalidate) {            canvas.drawText(middleNum, middlePoint.getX(), middlePoint.getY(), mPaint);            isMiddleNumInvalidate = false;        }        if (isRightNumInvalidate) {            canvas.drawText(rightNum, rightPoint.getX(), rightPoint.getY(), mPaint);            isRightNumInvalidate = false;        }    }    /**     * 开始动画     */    private void startAnimation() {        startLeft();        startMiddle();        startRight();    }    private void startRight() {        final CustomPoint startPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 + roundRadius / 2, (float) (getMeasuredHeight() / 2 - roundRadius * (Math.sqrt(3) / 2) - textRect.height() / 2));        final CustomPoint endPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 + roundRadius / 2, (float) (getMeasuredHeight() / 2 + roundRadius * (Math.sqrt(3) / 2) + textRect.height() / 2));        rightAnim = ValueAnimator.ofObject(new CustomPointEvaluator(), startPoint, endPoint);        rightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                rightPoint = (CustomPoint) animation.getAnimatedValue();                isRightNumInvalidate = true;                invalidate();            }        });        rightAnim.addListener(new CustomAnimListener() {            @Override            public void onAnimationRepeat(Animator animation) {                rightNum = getRandom();            }        });        rightAnim.setStartDelay(150);        rightAnim.setDuration(300);        rightAnim.setRepeatCount(ValueAnimator.INFINITE);    }    private void startMiddle() {        //初始化两头数字的开始点的地位        final CustomPoint startPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2, getMeasuredHeight() / 2 - roundRadius - textRect.height() / 2);        //初始化两头数字的完结点的地位        final CustomPoint endPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2, getMeasuredHeight() / 2 + roundRadius + textRect.height() / 2);        middleAnim = ValueAnimator.ofObject(new CustomPointEvaluator(), startPoint, endPoint);        //监听从起始点到起点过程中点的变动,并获取点而后从新绘制界面        middleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                middlePoint = (CustomPoint) animation.getAnimatedValue();                isMiddleNumInvalidate = true;                invalidate();            }        });        middleAnim.addListener(new CustomAnimListener() {            @Override            public void onAnimationRepeat(Animator animation) {                middleNum = getRandom();            }        });        middleAnim.setDuration(300);        middleAnim.setRepeatCount(ValueAnimator.INFINITE);    }    private void startLeft() {        //属性动画        final CustomPoint startPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 - roundRadius / 2, (float) (getMeasuredHeight() / 2 - roundRadius * (Math.sqrt(3) / 2) - textRect.height() / 2));        final CustomPoint endPoint = new CustomPoint(getMeasuredWidth() / 2 - textRect.width() / 2 - roundRadius / 2, (float) (getMeasuredHeight() / 2 + roundRadius * (Math.sqrt(3) / 2) + textRect.height() / 2));        leftAnim = ValueAnimator.ofObject(new CustomPointEvaluator(), startPoint, endPoint);        leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                leftPoint = (CustomPoint) animation.getAnimatedValue();                isLeftNumInvalidate = true;                invalidate();            }        });        leftAnim.addListener(new CustomAnimListener() {            @Override            public void onAnimationRepeat(Animator animation) {                middleNum = getRandom();            }        });        leftAnim.setStartDelay(100);        leftAnim.setDuration(300);        leftAnim.setRepeatCount(ValueAnimator.INFINITE);    }    /**     * 获取0-9之间的随机数     *     * @return     */    private String getRandom() {        int random = (int) (Math.random() * 9);        return String.valueOf(random);    }}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:lsp="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.ruan.mygitignore.CustomNumAnimView        android:id="@+id/custom"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        lsp:round_radius="50dp"        lsp:text_size="16dp"/></LinearLayout>

这是一个自定view的应用的自定义属性

结尾:每一个小小的提高,都是日后的财产