自定义view--打折标签view

自定义View

打折标签,数量增减可带动画效果。底部下载链接里的代码不是最新,本文才是。
这里写图片描述

  • 学习心得

    1. 创建自定义view,首先分析所需的界面显示以及功能需求,然后确定自身所需的自定义属性,创建attr文件。
    2. 接下来就是绘制部分的设计了。根据界面效果,拆分或者组合出所需要的效果。要注意的是我一般先写onDraw方,然后据此编写onMeasure进行测量自适应操作。按照调用顺序onMeasure、onDraw、onLayout进行调用,由于布局的层级深度可能会多次调用onMeasure等。一般我们要编写的就是这三个。
    3. 一般都是在构造函数里创建一个init方法,来获取自定义属性(attr),在获取结束后记得a.recycle();释放掉。
    4. 注意:在onDraw不要创建新的实例,这样减少不必要的开支。
  • attr类

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="OffFlagView">
        <attr name="offTopTitleTextSize" format="dimension"/>
        <attr name="offCenterTitleTextSize" format="dimension"/>
        <attr name="offTextBackgroundColor" format="color"/>
        <attr name="offIsAnim" format="boolean"/>
    </declare-styleable>
</resources>
  • view类





import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;




/**
 * author:   tc
 * date:     2015/12/11 & 16:04
 * version    1.0
 * description 折扣标签
 * modify by
 */
public class OffFlagView extends View {
    public static final String TAG = OffFlagView.class.getSimpleName();

    private int mTextBackgroundColor = -1;

    private String mTopText = "00%";
    private String mCenterText = "OFF";

    /**
     * op文本的大小
     */
    private int mTopTitleTextSize = 0;
    /**
     * center文本的大小
     */
    private int mCenterTitleTextSize = 0;
    private TextPaint mPaint;
    /**
     * 绘制时控制文本绘制的范围
     */
    private Rect mBound;
    /**
     * 是否启用数值变化动画
     */
    private boolean mIsAnim;
    private Path mPath;
    private int mPaddingTop;
    private int mPaddingLeft;
    private int mPaddingRight;
    private int mPaddingBottom;

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

    public OffFlagView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public OffFlagView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public OffFlagView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView(attrs);
    }

    public int getTopValue() {
        return mTopValue;
    }

    public void setTopValue(int topValue) {
        this.mTopText = String.valueOf(topValue + "%");
        this.mTopValue = topValue;
        if (mIsAnim) {
            this.startAnimation(anim);//动画形式的动态显示数值
        }
    }

    public String getCenterText() {
        return mCenterText;
    }

    public void setCenterText(String centerText) {
        this.mCenterText = centerText;
    }

    public int getTextBackgroundColor() {
        return mTextBackgroundColor;
    }

    public void setTextBackgroundColor(int textBackgroundColor) {
        this.mTextBackgroundColor = textBackgroundColor;
    }

    public int getTopTitleTextSize() {
        return mTopTitleTextSize;
    }

    public void setTopTitleTextSize(int topTitleTextSize) {
        this.mTopTitleTextSize = topTitleTextSize;
    }

    public int getCenterTitleTextSize() {
        return mCenterTitleTextSize;
    }

    public void setCenterTitleTextSize(int centerTitleTextSize) {
        this.mCenterTitleTextSize = centerTitleTextSize;
    }

    public boolean isIsAnim() {
        return mIsAnim;
    }

    public void setIsAnim(boolean mIsAnim) {
        this.mIsAnim = mIsAnim;
    }

    private void initView(AttributeSet attrs) {

        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.OffFlagView);
            mTopTitleTextSize = a.getDimensionPixelSize(R.styleable.OffFlagView_offTopTitleTextSize, 0);
            mCenterTitleTextSize = a.getDimensionPixelSize(R.styleable.OffFlagView_offCenterTitleTextSize, 0);
            mTextBackgroundColor = a.getResourceId(R.styleable.OffFlagView_offTextBackgroundColor, -1);
            mIsAnim = a.getBoolean(R.styleable.OffFlagView_offIsAnim, false);
            a.recycle();
        }
        /**
         * 获得绘制文本的宽和高
         */
        mPaint = new TextPaint();
        mBound = new Rect();
        mPaint.setTextSize(mTopTitleTextSize);
        mPaint.getTextBounds(mTopText, 0, mTopText.length(), mBound);
        mPath = new Path();
        anim = new BarAnimation();
        anim.setDuration(1000);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width;
        int height;
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            mPaint.setTextSize(mTopTitleTextSize);
            if (mTopText.length() >= 3) {
                mPaint.getTextBounds(mTopText, 0, mTopText.length(), mBound);
            } else {
                mPaint.getTextBounds("00%", 0, 3, mBound);//可能打折的数值是4%这种2位长度,所以宽度计算需要调整,避免小于OFF的宽度。
            }
            float textWidth = mBound.width();
            mPaddingLeft = getPaddingLeft() <= 0 ? dip2px(getContext(), 2) : getPaddingLeft();
            mPaddingRight = getPaddingRight() <= 0 ? dip2px(getContext(), 2) : getPaddingRight();
            width = (int) (mPaddingLeft + textWidth + mPaddingRight);
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            mPaint.setTextSize(mTopTitleTextSize);
            mPaint.getTextBounds(mTopText, 0, mTopText.length(), mBound);
            float textHeight = mBound.height();
            mPaddingTop = getPaddingTop() <= 0 ? dip2px(getContext(), 5) : getPaddingTop();
            mPaddingBottom = getPaddingBottom();
            height = (int) (mPaddingTop * 2 + textHeight * 3 + mPaddingBottom);
        }


        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int canvasWidth = canvas.getWidth();

        int canvasHeight = canvas.getHeight();
        int threeCanvasHeight = canvasHeight / 3;

        if (mTopTitleTextSize <= 0) {
            mTopTitleTextSize = dip2px(getContext(), 10);
        }
        if (mCenterTitleTextSize <= 0) {
            mCenterTitleTextSize = dip2px(getContext(), 10);
        }
        if (mTextBackgroundColor != -1) {
            mPaint.setColor(getContext().getResources().getColor(mTextBackgroundColor));
        }
        mPaint.setAntiAlias(true);//无齿轮感
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿

        mPath.moveTo(0, 0);// 此点为多边形的起点
        mPath.lineTo(canvasWidth, 0);
        mPath.lineTo(canvasWidth, threeCanvasHeight * 2 + mPaddingTop);
        mPath.lineTo(0, threeCanvasHeight * 2 + mPaddingTop);
        mPath.close(); // 使这些点构成封闭的多边形
        canvas.drawPath(mPath, mPaint);

        mPath.reset();
        mPath.moveTo(0, threeCanvasHeight * 2 + mPaddingTop);// 此点为多边形的起点
        mPath.lineTo(canvasWidth / 2, threeCanvasHeight * 2 + mPaddingTop);
        mPath.lineTo(0, canvasHeight);
        mPath.close(); // 使这些点构成封闭的多边形
        canvas.drawPath(mPath, mPaint);

        mPath.reset();
        mPath.moveTo(canvasWidth / 2, threeCanvasHeight * 2 + mPaddingTop);// 此点为多边形的起点
        mPath.lineTo(canvasWidth, threeCanvasHeight * 2 + mPaddingTop);
        mPath.lineTo(canvasWidth, canvasHeight);
        mPath.close(); // 使这些点构成封闭的多边形
        canvas.drawPath(mPath, mPaint);

        mPaint.reset();
        mPaint.setTextSize(mTopTitleTextSize);
        mPaint.setColor(getContext().getResources().getColor(R.color.white));
        mPaint.setAntiAlias(true);//无齿轮感
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿
        mPaint.setTypeface(Typeface.DEFAULT_BOLD);//加粗
        //设置居中对齐

        mPaint.setTextAlign(Paint.Align.CENTER);//设置居中对齐
        canvas.save();
        canvas.translate(canvasWidth / 2, threeCanvasHeight / 2 + mPaddingTop);
        canvas.drawText(mTopText, 0, 0, mPaint);
        canvas.restore();

        mPaint.setTextSize(mCenterTitleTextSize);
        mPaint.setTextAlign(Paint.Align.CENTER);//设置居中对齐
        canvas.save();
        canvas.translate(canvasWidth / 2, threeCanvasHeight + threeCanvasHeight / 2 + mPaddingTop);
        canvas.drawText(mCenterText, 0, 0, mPaint);
        canvas.restore();

    }

    private BarAnimation anim;
    private int mTopValue;//正在动画中的打折数值

    public class BarAnimation extends Animation {
        /**
         * Initializes expand collapse animation, has two types, collapse (1) and expand (0).
         */
        public BarAnimation() {
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                mTopText = String.valueOf((int) (interpolatedTime * mTopValue) + "%");
            } else {
                mTopText = String.valueOf(mTopValue + "%");
            }
            postInvalidate();
        }
    }


    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    private int dip2px(Context context, final float dpValue) {
        float density = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * density + 0.5f);
    }
}

源码下载地址:http://download.csdn.net/detail/u010716109/9424223

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值