美文网首页
自定义View--会呼吸的按钮

自定义View--会呼吸的按钮

作者: 半截铅笔 | 来源:发表于2018-04-28 17:51 被阅读32次
需求:用户点击按钮,切换到播放状态,按钮展示变换背景色效果,展现为呼吸样式.

效果图,如下:


图片.png

代码:

package com.kaike.la.framework.view.widget;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.kaike.la.framework.R;

import java.util.ArrayList;
import java.util.List;

import static com.kaike.la.framework.view.widget.BlnPlayView.Status.DEFAULT;
import static com.kaike.la.framework.view.widget.BlnPlayView.Status.PAUSE;
import static com.kaike.la.framework.view.widget.BlnPlayView.Status.PLAY;

/**********************************************************
 * @文件名称:BlnPlayView
 * @文件作者:lyw
 * @创建时间:2018/4/25 11:30
 * @文件描述:呼吸效果按钮
 * @修改历史:2018/4/25 创建初始版本
 **********************************************************/

public class BlnPlayView extends View {

    //计算渐变色~~~
    private final ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();
    private ValueAnimator mAnimator = null;

    //渐变色差值~~~
    private final List<Integer> mBlnColorResIds = new ArrayList<>();

    private final Paint mFunPaint = new Paint();
    private final Paint mBgBlnPaint = new Paint();

    private Rect mFunRect = null;

    private int mCenterX = 0;
    private int mCenterY = 0;

    //渐变持续时间~~
    private int mBlnPeriod = 2000;

    //当前该显示默认色~~~
    private int mBlnBgDefault = R.color.color_3329305c;
    //当前的颜色,渐变色使用~~~
    private int mBlnBgCurrent;

    private Bitmap mBlnFunDefault = null;
    private Bitmap mBlnFunPlay = null;
    private Bitmap mBlnFunPause = null;

    private int mBlnBgMeasure = 140;
    private int mBlnFunMeasure = 52;


    //当前状态~~~
    private int mMode = Status.PLAY;

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

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

    public BlnPlayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initView();
    }

    private void initAttrs(Context context, @Nullable AttributeSet attrs) {
        final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BlnPlayView);

        mBlnPeriod = array.getInt(R.styleable.BlnPlayView_blnPeriod, mBlnPeriod);

        mBlnBgDefault = array.getResourceId(R.styleable.BlnPlayView_blnBgDefault, mBlnBgDefault);

        mBlnFunDefault = BitmapFactory.decodeResource(getResources(), array.getResourceId(R.styleable.BlnPlayView_blnFunDrawableDefault, R.drawable.ic_fun_asr_play_default_cyan));
        mBlnFunPlay = BitmapFactory.decodeResource(getResources(), array.getResourceId(R.styleable.BlnPlayView_blnFunPlayDrawable, R.drawable.ic_fun_asr_play_cyan));
        mBlnFunPause = BitmapFactory.decodeResource(getResources(), array.getResourceId(R.styleable.BlnPlayView_blnFunPauseDrawable, R.drawable.ic_fun_asr_pause_cyan));

        mBlnBgMeasure = array.getDimensionPixelSize(R.styleable.BlnPlayView_blnBgMeasure, mBlnBgMeasure);
        mBlnFunMeasure = array.getDimensionPixelSize(R.styleable.BlnPlayView_blnFunMeasure, mBlnFunMeasure);
        array.recycle();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        resetCondition();
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if (hasWindowFocus) {
            if (Status.DEFAULT == getMode()) {
                showDefault();
            } else if (Status.PAUSE == getMode()) {
                showPause();
            } else {
                showPlay();
            }
        } else {
            resetCondition();
        }
    }

    /**
     * 初始化相关数据~~~
     */
    private void initView() {
        //设置默认渐变色~~~
        initBlnColor();
        //初始化paint~~
        initPaints();
    }

    /**
     * 初始化 paint
     */
    private void initPaints() {
        mFunPaint.setAntiAlias(true);
        mFunPaint.setFlags(Paint.FILTER_BITMAP_FLAG);

        mBgBlnPaint.setAntiAlias(true);
        mBgBlnPaint.setStyle(Paint.Style.FILL);
    }

    //初始化渐变色~~~
    private void initBlnColor() {
        mBlnColorResIds.add(R.color.color_29305C);
        mBlnColorResIds.add(R.color.color_37417A);
        mBlnColorResIds.add(R.color.color_29305C);
        mBlnBgCurrent = ContextCompat.getColor(getContext(), mBlnColorResIds.get(0));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = measureDimension(mBlnBgMeasure, widthMeasureSpec);
        int height = measureDimension(mBlnBgMeasure, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    public int measureDimension(int defaultSize, int measureSpec) {
        int result;

        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        // 父结点要求其子节点的大小指定为某个确切的值。其子节点以及其他子孙结点都需要适应该大小
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            //父结点对子结点的大小没有任何要求
            result = defaultSize;   //UNSPECIFIED
            if (specMode == MeasureSpec.AT_MOST) {
                //父结点要求其子节点的大小不能超过某个最大值,其子节点以及其他子孙结点的大小都需要小于这个值
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        mCenterX = (getWidth() + getPaddingLeft() - getPaddingRight()) / 2;
        mCenterY = (getHeight() + getPaddingTop() - getPaddingBottom()) / 2;

        mFunRect = new Rect(mCenterX - mBlnFunMeasure / 2,
                mCenterY - mBlnFunMeasure / 2,
                mCenterX + mBlnFunMeasure / 2,
                mCenterY + mBlnFunMeasure / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制~~~
        switch (getMode()) {
            case DEFAULT:
                drawDefault(canvas);
                break;
            case PAUSE:
                drawPause(canvas);
                break;
            case PLAY:
                drawPlay(canvas);
                break;
        }
    }

    /**
     * 绘制 渐变色背景,暂停按钮~~~
     */
    private void drawPlay(Canvas canvas) {
        drawCircleBg(canvas, false);

        drawablePlay(canvas, false);
    }

    /**
     * 绘制背景,播放按钮~~~
     */
    private void drawPause(Canvas canvas) {
        drawCircleBg(canvas, false);

        drawablePause(canvas);
    }

    /**
     * 绘制 背景,暂停按钮~~~ 不可点击状态~~~
     */
    private void drawDefault(Canvas canvas) {
        drawCircleBg(canvas, true);

        drawablePlay(canvas, true);
    }

    /**
     * 绘制暂停按钮~~~
     *
     * @param canvas
     */
    private void drawablePause(Canvas canvas) {
        canvas.drawBitmap(mBlnFunPause, null, mFunRect, mFunPaint);
    }

    /**
     * 绘制播放按钮~~~
     *
     * @param canvas
     * @param isDefault
     */
    private void drawablePlay(Canvas canvas, boolean isDefault) {
        if (isDefault) {
            canvas.drawBitmap(mBlnFunDefault, null, mFunRect, mFunPaint);
        } else {
            canvas.drawBitmap(mBlnFunPlay, null, mFunRect, mFunPaint);
        }
    }

    /**
     * 绘制原型背景~~~
     *
     * @param canvas
     * @param isDefault
     */
    private void drawCircleBg(Canvas canvas, boolean isDefault) {
        if (isDefault) {
            //不可使用时,设置为默认色~~~
            mBgBlnPaint.setColor(ContextCompat.getColor(getContext(), mBlnBgDefault));
        } else {
            //可以使用,显示为渐变色的第一个色值~~~
            mBgBlnPaint.setColor(mBlnBgCurrent);
        }
        canvas.drawCircle(mCenterX, mCenterY, mBlnBgMeasure / 2, mBgBlnPaint);
    }

    /**
     * 显示默认状态~~~
     */
    public void showDefault() {
        resetCondition();
        this.mMode = Status.DEFAULT;
        invalidate();
    }

    /**
     * 显示暂停~~~
     */
    public void showPause() {
        resetCondition();
        this.mMode = Status.PAUSE;
        showBln();
    }

    /**
     * 显示播放~~~
     */
    public void showPlay() {
        resetCondition();
        this.mMode = Status.PLAY;
        invalidate();
    }

    /**
     * 启动定时器~~~
     */
    private void showBln() {
        mAnimator = ValueAnimator.ofInt(0, (mBlnColorResIds.size() - 1) * 10);
        mAnimator.setDuration(mBlnPeriod);
        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mAnimator.setRepeatMode(ValueAnimator.RESTART);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.addUpdateListener(updateListener);
        mAnimator.start();
    }

    /**
     * 初始化相关状态~~~
     */
    private void resetCondition() {
        //恢复相关变量初始值~~~
        mBlnBgCurrent = ContextCompat.getColor(getContext(), mBlnColorResIds.get(0));
        if (null != mAnimator) {
            mAnimator.cancel();
            mAnimator = null;
        }
    }

    /**
     * 设置渐变色数据数组
     */
    public void setBlnColors(List<Integer> blnColorResIds) {
        if (null == blnColorResIds || blnColorResIds.isEmpty()) {
            return;
        }
        this.mBlnColorResIds.clear();
        this.mBlnColorResIds.addAll(blnColorResIds);
        mBlnBgCurrent = ContextCompat.getColor(getContext(), mBlnColorResIds.get(0));
    }

    /**
     * 设置 渐变持续时间~~~
     *
     * @param second
     */
    public void setBlnPeriod(int second) {
        if (second < 0) {
            mBlnPeriod = 1000;
        } else {
            mBlnPeriod = second;
        }
    }

    /**
     * 获取当前的mode
     *
     * @return
     */
    public int getMode() {
        return mMode;
    }


    private ValueAnimator.AnimatorUpdateListener updateListener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            //0-100~~~

            final int value = (int) animation.getAnimatedValue();
            //求余数~~~
            final int remainder = value % 10;
            //求商~~~
            final int quotient = value / 10;

            final float fraction = remainder / 10.0f;

            final int start = ContextCompat.getColor(getContext(), mBlnColorResIds.get(quotient));
            final int end = ContextCompat.getColor(getContext(), mBlnColorResIds.get(quotient + 1));

            //计算对应的颜色~~~
            mBlnBgCurrent = (int) (mArgbEvaluator.evaluate(fraction, start, end));

            invalidate();
        }
    };

    @IntDef({DEFAULT, PAUSE, PLAY})
    @interface Status {

        //默认状态~~~
        int DEFAULT = 0;

        //暂停状态~~~
        int PAUSE = 1;

        //播放状态~~~
        int PLAY = 2;
    }

}

相关文章

网友评论

      本文标题:自定义View--会呼吸的按钮

      本文链接:https://www.haomeiwen.com/subject/knxnlftx.html