仿饿了么 + - 自定义View

我们的效果图

在录制gif的时候有点卡顿,感觉控件中的动画看得不是很清楚,此自定义控件是有旋转和向右扩展和收缩的效果的

自定义属性


    <declare-styleable name="AnimShopButton">
        
        <attr name="isAddFillMode" format="boolean"/>
        
        <attr name="addEnableBgColor" format="color"/>
        <attr name="addEnableFgColor" format="color"/>
        
        <attr name="addDisableBgColor" format="color"/>
        <attr name="addDisableFgColor" format="color"/>

        
        <attr name="isDelFillMode" format="boolean"/>
        
        <attr name="delEnableBgColor" format="color"/>
        <attr name="delEnableFgColor" format="color"/>
        
        <attr name="delDisableBgColor" format="color"/>
        <attr name="delDisbleFgColor" format="color"/>

        
        <attr name="radius" format="dimension"/>
        
        <attr name="circleStrokeWidth" format="dimension"/>
        
        <attr name="lineWidth" format="dimension"/>

        
        <attr name="gapBetweenCircle" format="dimension"/>
        
        <attr name="numTextSize" format="dimension"/>
        
        <attr name="maxCount" format="integer"/>
        <attr name="count" format="integer"/>

        
        <attr name="ignoreHintArea" format="boolean"/>

        
        <attr name="hintText" format="string"/>
        <attr name="hintBgColor" format="color"/>
        <attr name="hintFgColor" format="color"/>
        <attr name="hintTextSize" format="dimension"/>
        <attr name="hintBgRoundValue" format="dimension"/>

        <attr name="perAnimDuration" format="integer"/>

        
        <attr name="replenishTextSize" format="dimension"/>
        <attr name="replenishTextColor" format="color"/>
        <attr name="replenishText" format="string"/>

    declare-styleable>

此控件一共有三种状态:

1.商品无货 这里写图片描述
2.有货但是还没选择数量这里写图片描述
3,诱惑选择的数量>0这里写图片描述

自定义view的所有代码

public class AnimShopButton extends View{

    protected static final String TAG = AnimShopButton.class.getName();
    protected static final int DEFAULT_DURATION = 350;
    //控件paddingLeft,paddingTop.+ paint的width
    protected int mLeft,mTop;
    protected int mWidth,mHeight;

    //加减的圆的path和Region
    protected Region mAddRegion,mDelRegion;
    protected Path mAddPath,mDelPath;

    /**
     * 加按钮
     */
    protected Paint mAddPaint;
    //加按钮是否开启fill模式.默认是false
    protected boolean isAddFillMode;
    //加按钮的背景色前景色
    protected int mAddEnableBgColor;
    protected int mAddEnableFgColor;
    //加按钮不可用时的背景色前景色
    protected int mAddDisableBgColor;
    protected int mAddDisableFgColor;

    /**
     * 减按钮
     */
    protected Paint mDelPaint;
    //按钮是否开启fill模式,默认是storke(false)
    protected boolean isDelFillMode;
    //按钮的背景色前景色
    protected int mDelEnableBgColor;
    protected int mDelEnableFgColor;
    //按钮不可用时的背景色前景色
    protected int mDelDisableBgColor;
    protected int mDelDisableFgColor;

    //最大数量和当前数量
    protected int mMaxCount;
    protected int mCount;

    //圆的半径
    protected float mRadius;
    //圆圈的宽度
    protected float mCircleWidth;
    //线的宽度
    protected float mLineWidth;

    /**
     * 两个圆之间的间距
     */
    protected float mGapBetweenCircle;
    //绘制数量的Textsize
    protected float mTextSize;
    protected Paint mTextPaint;
    protected Paint.FontMetrics mFontMetrics;

    //动画的基准值,动画:减0~1,加1~0;
    //普通状态下都是显示的0
    protected ValueAnimator mAnimAdd,mAnimDel;
    protected float mAnimFraction;

    //展开,加入购物车动画
    protected ValueAnimator mAnimExpandHint;
    protected ValueAnimator mAnimReduceHint;

    protected int mPerAnimDuration = DEFAULT_DURATION;

    /**
     * 增加一个开关,ignoreHintArea:UI显示,动画是否忽略hint收缩区域
     */
    protected boolean ignoreHintArea;

    //是否处于hintmode下count=0时,且第一段动画做完了.是true
    protected boolean isaHintMode;

    //提示语收缩动画 0-1,展开1-0
    //普通模式时,应该是1,只在isHintMode true才有效
    protected float mAnimExpandHintFraction;

    //展开动画结束后才显示文字
    protected boolean isShowHintText;

    //数量为0时.hint文字背景色前景色大小
    protected Paint mHintPaint;
    protected int mHintBgColor;
    protected int mHintTextSize;
    protected String mHintText;
    protected int mHintFgColor;

    /**
     * 圆角值
     */
    protected int mHintBgRoundValue;

    //Feature : 显示正在补货中,此时不允许点击
    protected boolean isReplenish;
    //画笔,颜色,大小文字
    protected Paint mReplenishPaint;
    protected int mReplenishTextColor;
    protected int mReplenishTextSize;
    protected String mReplenishText;

    //点击回调
    protected IOnAddDelListener mOnAddDelListener;




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

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

    public AnimShopButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs,defStyleAttr);
    }


    public int getCount() {
        return mCount;
    }

    /**
     * 设置当前的数量
     */
    public AnimShopButton setCount(int c) {
        mCount = c;
        //先暂停所有动画
        cancelAllAnim();

        //复用机制的处理
        initAnimSettingsByCount();
        return this;
    }

    /**
     * 根据当前count数量,初始化hint提示语相关变量
     */
    private void initAnimSettingsByCount() {

        mAnimFraction = mCount == 0 ? 1 : 0;
        if (mCount == 0) {
            isaHintMode = true;
            isShowHintText = true;
            mAnimExpandHintFraction = 0;
        } else {
            isaHintMode = false;
            isShowHintText = false;
            mAnimExpandHintFraction = 1;
        }
    }

    /**
     * 暂停所有动画
     */
    private void cancelAllAnim() {
        if (mAnimAdd != null && mAnimAdd.isRunning()) {
            mAnimAdd.cancel();
        }
        if (mAnimDel != null && mAnimDel.isRunning()) {
            mAnimDel.cancel();
        }
        if (mAnimExpandHint != null && mAnimExpandHint.isRunning()) {
            mAnimExpandHint.cancel();
        }
        if (mAnimReduceHint != null && mAnimReduceHint.isRunning()) {
            mAnimReduceHint.cancel();
        }
    }

    public IOnAddDelListener getIOnAddDelListener() {
        return mOnAddDelListener;
    }

    public int getMaxCount() {
        return mMaxCount;
    }

    /**
     * 设置最大数量
     */
    public AnimShopButton setMaxCount(int c) {
        mMaxCount = c;
        return this;
    }

    public boolean isReplenish() {
        return isReplenish;
    }

    public AnimShopButton setIsReplenish(boolean replenish) {
        isReplenish = replenish;
        if (isReplenish && null == mReplenishPaint) {
            mReplenishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mReplenishPaint.setTextSize(mReplenishTextSize);
            mReplenishPaint.setColor(mReplenishTextColor);
        }
        return this;
    }

    public int getReplenishTextColor() {
        return mReplenishTextColor;
    }
    public AnimShopButton setReplenishTextColor(int color) {
        mReplenishTextColor = color;
        return this;
    }

    public int getReplenishTextSize() {
        return mReplenishTextSize;
    }

    public AnimShopButton setReplenishTextSize(int replenishTextSize) {
        this.mReplenishTextSize = replenishTextSize;
        return this;
    }

    public String getReplenishText() {
        return mReplenishText;
    }

    public AnimShopButton setReplenshiText(String replenshiText) {
        mReplenishText = replenshiText;
        return this;
    }

    public boolean isAddFillMode() {
        return isAddFillMode;
    }

    public AnimShopButton setAddFillMode(boolean addFillMode) {
        isAddFillMode = addFillMode;
        return this;
    }

    public int getAddEnableBgColor() {
        return mAddEnableBgColor;
    }

    public AnimShopButton setAddEnableBgColor(int addEnableBgColor) {
        mAddEnableBgColor = addEnableBgColor;
        return this;
    }

    public int getAddEnableFgColor() {
        return mAddEnableFgColor;
    }

    public AnimShopButton setAddEnableFgColor(int addEnableFgColor) {
        mAddEnableFgColor = addEnableFgColor;
        return this;
    }

    public int getAddDisableBgColor() {
        return mAddDisableBgColor;
    }

    public AnimShopButton setAddDisableBgColor(int addDisableBgColor) {
        mAddDisableBgColor = addDisableBgColor;
        return this;
    }

    public int getAddDisableFgColor() {
        return mAddDisableFgColor;
    }

    public AnimShopButton setAddDisableFgColor(int addDisableFgColor) {
        mAddDisableFgColor = addDisableFgColor;
        return this;
    }

    public boolean isDelFillMode() {
        return isDelFillMode;
    }

    public AnimShopButton setIsDelFillMode(boolean isDelFillMode) {
        this.isDelFillMode = isDelFillMode;
        return this;
    }

    public int getDelEnableBgColor(){
        return mDelEnableBgColor;
    }

    public AnimShopButton setDelEnableBgColor(int delEnableBgColor) {
        mDelEnableBgColor = delEnableBgColor;
        return this;
    }

    public int getDelEnableFgColor() {
        return mDelEnableFgColor;
    }

    public AnimShopButton setDelEnableFgColor(int delEnableFgColor) {
        mDelEnableFgColor = delEnableFgColor;
        return this;
    }

    public int getDelDisableBgColor() {
        return mDelDisableBgColor;
    }

    public AnimShopButton setDelDisableBgColor(int delDisableBgColor) {
        mDelDisableBgColor = delDisableBgColor;
        return this;
   }
    public int getDelDisableFgColor() {
        return mDelDisableFgColor;
    }

    public AnimShopButton setDelDisableFgColor(int delDisableFgColor){
        mDelDisableFgColor = delDisableFgColor;
        return this;
    }

    public float getRadius() {
        return mRadius;
    }

    public AnimShopButton setRadius(float radius) {
        mRadius = radius;
        return this;
    }

    public float getCircleWidth() {
        return mCircleWidth;
    }

    public AnimShopButton setCircleWidth(float circleWidth) {
        mCircleWidth = circleWidth;
        return this;
    }

    public float getLineWidth() {
        return mLineWidth;
    }

    public AnimShopButton setLineWidth(float lineWidth) {
        mLineWidth = lineWidth;
        return this;
    }

    public float getTextSize() {
        return mTextSize;
    }

    public AnimShopButton setTextSize(float textSize) {
        mTextSize = textSize;
        return this;
    }

    public float getGapBetweenCircle() {
        return mGapBetweenCircle;
    }

    public AnimShopButton setGapBenweenCircle(float gapBenweenCircle) {
        mGapBetweenCircle = gapBenweenCircle;
        return this;
    }

    public int getPerAnimDuration() {
        return mPerAnimDuration;
    }

    public AnimShopButton setPerAnimDuration(int perAnimDuration) {
        mPerAnimDuration = perAnimDuration;
        return this;
    }

    public boolean isIgnoreHintArea() {
        return ignoreHintArea;
    }

    public AnimShopButton setIgnoreHintArea(boolean ignoreHintArea) {
        this.ignoreHintArea = ignoreHintArea;
        return this;
    }

    public int getHintBgColor()
    {
        return mHintBgColor;
    }

    public AnimShopButton setHintBgColor(int hintBgColor){
        this.mHintBgColor = hintBgColor;
        return this;
    }

    public int getHintTextSize() {
        return mHintTextSize;
    }

    public AnimShopButton setHintTextSize(int hintTextSize) {
        mHintTextSize = hintTextSize;
        return this;
    }

    public String getHintText() {
        return mHintText;
    }

    public AnimShopButton setHintText(String hintText) {
        mHintText = hintText;
        return this;
    }

    public int getHintFgColor() {
        return mHintFgColor;
    }

    public AnimShopButton setHintFgColor(int hintFgColor) {
        mHintFgColor = hintFgColor;
        return this;
    }

    public int getHintBgRoundValue() {
        return mHintBgRoundValue;
    }

    public AnimShopButton setHintBgRoundValue(int hintBgRoundValue) {
        mHintBgRoundValue = hintBgRoundValue;
        return this;
    }

    /**
     * 设置加减监听器
     * @param iOnAddDelListener
     * @return
     */
    public AnimShopButton setOnAddDelListener(IOnAddDelListener iOnAddDelListener) {
        mOnAddDelListener = iOnAddDelListener;
        return this;
    }




    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        //模拟参数传入设置初始值
        initDefaultValue(context);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AnimShopButton,defStyleAttr,0);
        int indexCount = a.getIndexCount();
        for (int i = 0 ; i < indexCount ; i++) {
            int index = a.getIndex(i);
            switch (index) {
                case R.styleable.AnimShopButton_gapBetweenCircle:
                    mGapBetweenCircle = a.getDimension(index,mGapBetweenCircle);
                    break;
                case R.styleable.AnimShopButton_isAddFillMode:
                    isAddFillMode = a.getBoolean(index,isAddFillMode);
                    break;
                case R.styleable.AnimShopButton_addEnableBgColor:
                    mAddEnableBgColor = a.getColor(index,mAddEnableBgColor);
                    break   ;
                case R.styleable.AnimShopButton_addEnableFgColor:
                    mAddEnableFgColor = a.getColor(index,mAddEnableFgColor);
                    break;
                case R.styleable.AnimShopButton_addDisableBgColor:
                    mAddDisableBgColor = a.getColor(index,mAddDisableBgColor);
                    break;
                case R.styleable.AnimShopButton_addDisableFgColor:
                    mAddDisableFgColor = a.getColor(index,mAddDisableFgColor);
                    break;
                case R.styleable.AnimShopButton_isDelFillMode:
                    isDelFillMode = a.getBoolean(index,isDelFillMode);
                    break;
                case R.styleable.AnimShopButton_delEnableBgColor:
                    mDelEnableBgColor = a.getColor(index,mDelEnableBgColor);
                    break;
                case R.styleable.AnimShopButton_delEnableFgColor:
                    mDelEnableFgColor = a.getColor(index,mDelEnableFgColor);
                    break;
                case R.styleable.AnimShopButton_delDisableBgColor:
                    mDelDisableBgColor = a.getColor(index,mDelDisableBgColor);
                    break;
                case R.styleable.AnimShopButton_delDisbleFgColor:
                    mDelDisableFgColor = a.getColor(index,mDelDisableFgColor);
                    break;
                case R.styleable.AnimShopButton_maxCount:
                    mMaxCount = a.getInteger(index,mMaxCount);
                    break;
                case R.styleable.AnimShopButton_count:
                    mCount = a.getInteger(index,mCount);
                    break;
                case R.styleable.AnimShopButton_radius:
                    mRadius = a.getDimension(index,mRadius);
                    break;
                case R.styleable.AnimShopButton_circleStrokeWidth:
                    mCircleWidth = a.getDimension(index,mCircleWidth);
                    break;
                case R.styleable.AnimShopButton_lineWidth:
                    mLineWidth = a.getDimension(index,mLineWidth);
                    break;
                case R.styleable.AnimShopButton_numTextSize:
                    mTextSize = a.getDimension(index,mTextSize);
                    break;
                case R.styleable.AnimShopButton_hintText:
                    mHintText = a.getString(index);
                    break;
                case R.styleable.AnimShopButton_hintBgColor:
                    mHintBgColor = a.getColor(index,mHintBgColor);
                    break;
                case R.styleable.AnimShopButton_hintFgColor:
                    mHintFgColor = a.getColor(index,mHintFgColor);
                    break;
                case R.styleable.AnimShopButton_hintTextSize:
                    mHintTextSize = a.getDimensionPixelSize(index,mHintTextSize);
                    break;
                case R.styleable.AnimShopButton_hintBgRoundValue:
                    mHintBgRoundValue = a.getDimensionPixelOffset(index,mHintBgRoundValue);

                    break;
                case R.styleable.AnimShopButton_ignoreHintArea:
                    ignoreHintArea = a.getBoolean(index,false);
                    break;
                case R.styleable.AnimShopButton_perAnimDuration:
                    mPerAnimDuration = a.getInteger(index,DEFAULT_DURATION);
                    break;
                case R.styleable.AnimShopButton_replenishText:
                    mReplenishText = a.getString(index);
                    break;
                case R.styleable.AnimShopButton_replenishTextColor:
                    mReplenishTextColor = a.getColor(index,mReplenishTextColor);
                    break;
                case R.styleable.AnimShopButton_replenishTextSize:
                    mReplenishTextSize = a.getDimensionPixelSize(index,mReplenishTextSize);

                    break;
            }

        }
        a.recycle();
        mAddRegion = new Region();
        mDelRegion = new Region();
        mAddPath = new Path();
        mDelPath = new Path();

        mAddPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        if (isAddFillMode) {
            mAddPaint.setStyle(Paint.Style.FILL);
        }else {
            mAddPaint.setStyle(Paint.Style.STROKE);
        }
        mDelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        if (isDelFillMode) {
            mDelPaint.setStyle(Paint.Style.FILL);
        }else {
            mDelPaint.setStyle(Paint.Style.STROKE);
        }

        mHintPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHintPaint.setStyle(Paint.Style.FILL);
        mHintPaint.setTextSize(mHintTextSize);

        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(mTextSize);
        mFontMetrics = mTextPaint.getFontMetrics();

        //+动画
        mAnimAdd = ValueAnimator.ofFloat(1,0);
        mAnimAdd.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimFraction = (float) animation.getAnimatedValue();
                invalidate();
            }
        });

        mAnimAdd.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
        mAnimAdd.setDuration(mPerAnimDuration);

        //提示语收缩动画 0-1
        mAnimReduceHint = ValueAnimator.ofFloat(0,1);
        mAnimReduceHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimExpandHintFraction = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        mAnimReduceHint.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mCount >= 1) {
                    //底色不显示了
                    isaHintMode = false;
                }
                if (mCount >= 1) {
                    Log.d(TAG,"现在还是>=1 开始收缩动画");
                    if (mAnimAdd != null && !mAnimAdd.isRunning()) {
                        mAnimAdd.start();
                    }
                }
            }

            @Override
            public void onAnimationStart(Animator animation) {
                if (mCount == 1) {
                    //不显示文字了
                    isShowHintText = false;
                }
            }
        });
        mAnimReduceHint.setDuration(ignoreHintArea ? 0 : mPerAnimDuration);

        //动画 -
        mAnimDel = ValueAnimator.ofFloat(0,1);
        mAnimDel.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimFraction = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        //1-0;
        mAnimDel.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mCount == 0) {
                    Log.d(TAG,"现在还是0onAnimtionEnd() called with : animation = {"+ animation+"}");
                    if (mAnimExpandHint != null && !mAnimExpandHint.isRunning()){
                        mAnimExpandHint.start();
                    }
                }
            }
        });
        mAnimDel.setDuration(mPerAnimDuration);
        //提示语展开动画
        //分析这个动画,最初是个圆,就是left不断减小
        mAnimExpandHint = ValueAnimator.ofFloat(1,0);
        mAnimExpandHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimExpandHintFraction = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        mAnimExpandHint.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mCount == 0) {
                    isShowHintText = true;
                }
            }

            @Override
            public void onAnimationStart(Animator animation) {
                if (mCount == 0) {
                    isaHintMode = true;
                }
            }
        });
        mAnimExpandHint.setDuration(ignoreHintArea ? 0 : mPerAnimDuration);
    }

    private void initDefaultValue(Context context) {
        mGapBetweenCircle = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 34, context.getResources().getDisplayMetrics());

        isAddFillMode = true;
        mAddEnableBgColor = 0xFFFFDC5B;
        mAddEnableFgColor = Color.BLACK;
        mAddDisableBgColor = 0xff979797;
        mAddDisableFgColor = Color.BLACK;

        isDelFillMode = false;
        mDelEnableBgColor = 0xff979797;
        mDelEnableFgColor = 0xff979797;
        mDelDisableBgColor = 0xff979797;
        mDelDisableFgColor = 0xff979797;

/*        mMaxCount = 4;
        mCount = 1;*/

        mRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12.5f, getResources().getDisplayMetrics());
        mCircleWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, getResources().getDisplayMetrics());
        mLineWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, getResources().getDisplayMetrics());
        mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14.5f, getResources().getDisplayMetrics());

        mHintText = "加入购物车";
        mHintBgColor = mAddEnableBgColor;
        mHintFgColor = mAddEnableFgColor;
        mHintTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, context.getResources().getDisplayMetrics());
        mHintBgRoundValue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, context.getResources().getDisplayMetrics());

        mReplenishText = "补货中";
        mReplenishTextColor = 0xfff32d3b;
        mReplenishTextSize = mHintTextSize;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLeft = (int) (getPaddingLeft() + mCircleWidth);
        mTop = (int) (getPaddingTop() + mCircleWidth);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int hSize = MeasureSpec.getSize(heightMeasureSpec);

        switch(wMode) {
            case MeasureSpec.EXACTLY:
                break;
            case MeasureSpec.AT_MOST:
                //不超过父控件给的范围内自由发挥
                int computeSize = (int) (getPaddingLeft() + mRadius * 2 + mGapBetweenCircle + mRadius * 2 +getPaddingRight() + mCircleWidth * 2);
                wSize = computeSize < wSize ? computeSize : wSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                //自由发挥
                computeSize = (int) (getPaddingLeft() + mRadius * 2 + mGapBetweenCircle + mRadius * 2 + getPaddingRight() + mCircleWidth * 2);

                wSize = computeSize;
                break;
        }
        switch (hMode) {
            case MeasureSpec.EXACTLY:
                break;
            case MeasureSpec.AT_MOST:
                int computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);
                hSize = computeSize > hSize ? hSize : computeSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);
                hSize = computeSize;
                break;
        }
        setMeasuredDimension(wSize,hSize);

        //先暂停动画
        cancelAllAnim();
        //d复用时会走这里
        initAnimSettingsByCount();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (isReplenish) {
            //计算baseline绘制的起点x轴坐标
            int baseX = (int) (mWidth / 2 - mReplenishPaint.measureText(mReplenishText) / 2);
            //计算baseline绘制的起点y轴的坐标
            int baseY = (int) (mHeight / 2 - (mReplenishPaint.descent() + mReplenishPaint.ascent()) / 2);
            canvas.drawText(mReplenishText,baseX,baseY,mReplenishPaint);
            return;
        }

        if (!ignoreHintArea && isaHintMode) {
            //add hint 展开动画
            //if(mCount = 0)
            //背景
            mHintPaint.setColor(mHintBgColor);
            RectF rectF = new RectF(mLeft + (mWidth + mRadius * 2 ) * mAnimExpandHintFraction,mTop,
                    mWidth - mCircleWidth,mHeight - mCircleWidth);
            canvas.drawRoundRect(rectF,mHintBgRoundValue,mHintBgRoundValue,mHintPaint);
            if (isShowHintText) {
                //前景文字
                mHintPaint.setColor(mHintFgColor);
                //计算baseline绘制的起点x轴坐标
                int baseX = (int) (mWidth / 2 - mHintPaint.measureText(mHintText) / 2);
                //计算baseline绘制的y坐标
                int baseY = (int) (mHeight / 2 - (mHintPaint.descent() + mHintPaint.ascent()) / 2);
                canvas.drawText(mHintText,baseX,baseY,mHintPaint);
            }

        }else {
            //动画mAnimFraction 减 0 -1 加 1 - 0
            //动画位移max
            float animOffSetMazx = mRadius * 2 + mGapBetweenCircle;
            //透明度动画的基准
            int animAlphaMax = 255;
            int animRotateMax = 360;

            //左边 背景 圆
            if (mCount > 0) {
                mDelPaint.setColor(mDelEnableBgColor);
            }else {
                mDelPaint.setColor(mDelDisableBgColor);
            }
            mDelPaint.setAlpha((int) (animAlphaMax * (1 - mAnimFraction)));

            mDelPaint.setStrokeWidth(mCircleWidth);
            mDelPath.reset();//清除掉path中的线条和曲线,但是不会改变他的fill-type
            //改变圆心x坐标实现位移
            mDelPath.addCircle(animOffSetMazx * mAnimFraction + mLeft + mRadius,mTop + mRadius,mRadius, Path.Direction.CW);
            mDelRegion.setPath(mDelPath,new Region(mLeft,mTop,mWidth - getPaddingRight(),mHeight - getPaddingBottom()));

            canvas.drawPath(mDelPath,mDelPaint);

            //前景-
            if(mCount > 0) {
                mDelPaint.setColor(mDelEnableFgColor);
            }else {
                mDelPaint.setColor(mDelDisableFgColor);
            }
            mDelPaint.setStrokeWidth(mLineWidth);
            //旋转动画
            canvas.save();
            canvas.translate(animOffSetMazx * mAnimFraction + mLeft + mRadius,mTop + mRadius);
            canvas.rotate((animRotateMax * ( 1 - mAnimFraction)));
            canvas.drawLine(-mRadius / 2, 0 , +mRadius / 2,0,mDelPaint);
            canvas.restore();

            //数量
            canvas.save();
            //平移动画
            canvas.translate(mAnimFraction * (mGapBetweenCircle / 2 - mTextPaint.measureText(mCount+"") / 2 + mRadius),0);
            //旋转动画,旋转中心点,x是绘图中心,y是空间中心
            canvas.rotate(360 * mAnimFraction,(mGapBetweenCircle / 2 + mLeft + mRadius * 2),mTop + mRadius);
            //透明度变化
            mTextPaint.setAlpha((int) (255 * (1 - mAnimFraction)));
            //是没有动画的普通写法
            canvas.drawText(mCount + "",mGapBetweenCircle / 2 - mTextPaint.measureText(mCount + "") / 2 + mLeft + mRadius * 2
                    ,mTop + mRadius - (mFontMetrics.top + mFontMetrics.bottom) / 2,mTextPaint);
            canvas.restore();

            //右边背景圆
            if (mCount < mMaxCount) {
                mAddPaint.setColor(mAddEnableBgColor);
            }else {
                mAddPaint.setColor(mAddDisableBgColor);
            }
            mAddPaint.setStrokeWidth(mCircleWidth);
            float left = mLeft + mRadius * 2 + mGapBetweenCircle;
            mAddPath.reset();
            mAddPath.addCircle(left + mRadius,mTop + mRadius,mRadius, Path.Direction.CW);
            mAddRegion.setPath(mAddPath,new Region(mLeft,mTop,mWidth - getPaddingRight(),mHeight - getPaddingBottom()));
            canvas.drawPath(mAddPath,mAddPaint);

            //前景+
            if (mCount < mMaxCount) {
                mAddPaint.setColor(mAddEnableFgColor);
            }else {
                mAddPaint.setColor(mAddDisableFgColor);
            }
            mAddPaint.setStrokeWidth(mLineWidth);
            canvas.drawLine(left + mRadius / 2,mTop + mRadius,left + mRadius / 2 + mRadius,mTop + mRadius,mAddPaint);
            canvas.drawLine(left + mRadius,mTop + mRadius / 2,left + mRadius,mTop + mRadius / 2 + mRadius,mAddPaint);

        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (isReplenish) {
                    break;
                }
                //hint模式
                if (isaHintMode) {
                    onAddClick();
                    return true;
                }else {
                    if (mAddRegion.contains((int)event.getX(),(int)event.getY())){
                        onAddClick();
                        return true;
                    }else if (mDelRegion.contains((int) event.getX(),(int)event.getY())){
                        onDelClick();
                        return true;
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.onTouchEvent(event);
    }

    //使用时可以重写onDelClick()和onAddClick()方法,并在合适的时机回调onCountAddSuccess()和onCountDelSuccess()方法
    protected void onDelClick() {
        if(mCount > 0) {
            mCount--;
            onCountDelSuccess();
            if (null != mOnAddDelListener) {
                mOnAddDelListener.onDelSuccess(mCount);
            }
        }else {
            if (null != mOnAddDelListener) {
                mOnAddDelListener.onAddFailed(mCount,IOnAddDelListener.FailType.COUNT_MIN);
            }
        }
    }
    protected void onAddClick() {
        if (mCount < mMaxCount) {
            mCount++;
            onCountAddSuccess();
            if (null != mOnAddDelListener) {
                mOnAddDelListener.onAddSuccess(mCount);
            }
        }else {
            if (null != mOnAddDelListener) {
                mOnAddDelListener.onAddFailed(mCount,IOnAddDelListener.FailType.COUNT_MAX);
            }
        }
    }

    /**
     * 数量减少成功后,使用者回调以执行动画
     *
     */
    public void onCountDelSuccess() {
        if(mCount == 0) {
            cancelAllAnim();
            mAnimDel.start();
        }else {
            mAnimFraction = 0;
            invalidate();
        }

    }

    /**
     * 数量增加成功后,使用者回调以执行动画
     */
    public void onCountAddSuccess() {
        if (mCount == 1) {
            cancelAllAnim();
            mAnimReduceHint.start();
        }else {
            mAnimFraction = 0;
            invalidate();
        }

    }
    public interface IOnAddDelListener {
        enum FailType{
            COUNT_MAX,COUNT_MIN
        }

        void onAddSuccess(int count);

        void onAddFailed(int count, FailType failType);

        void onDelSuccess(int count);

        void onDelFailed(int count, FailType failType);

    }

}

文章前面的demo的布局文件

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_anim_shop_button"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.bailong.myapplication.AnimShopButtonActivity">
    "wrap_content"
        android:layout_height="wrap_content"
        android:text="补货中"
        />
    <com.example.bailong.myapplication.view.AnimShopButton
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:addEnableBgColor="#3190E8"
        app:addEnableFgColor="#ffffff"
        app:hintBgColor="#3190E8"
        app:hintBgRoundValue="15dp"
        app:hintFgColor="#ffffff"
        app:ignoreHintArea="true"
        app:maxCount="99"/>
    "wrap_content"
        android:layout_height="wrap_content"
        android:text="默认UI属性"
        />
    <com.example.bailong.myapplication.view.AnimShopButton
        android:id="@+id/asb_1"
        app:maxCount="3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:hintFgColor="#ffffff"
        />
    "wrap_content"
        android:layout_height="wrap_content"
        android:text="设置了两圆间距、hint和颜色、每段动画动画时间"/>
    <com.example.bailong.myapplication.view.AnimShopButton
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:count="3"
        app:gapBetweenCircle="90dp"
        app:hintFgColor="#ffffff"
        app:hintText="卫龙拉条,你值得拥有"
        app:maxCount="99"
        app:perAnimDuration="500"/>

        />

Activity里的代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anim_shop_button);

        AnimShopButton btn = (AnimShopButton) findViewById(R.id.btn1);
        btn.setIsReplenish(true);
    }

相关文章:

http://blog.csdn.net/zxt0601

你可能感兴趣的:(自定义view)