自定义电池充电动画

最近公司项目涉及到一个电池充电的效果,需要电量从底部上顶部逐渐变多,再变为0。反复循环。在借鉴了别人写的动画后,自己写了如下动画。里面有些代码是写死的,诸君可以自行修改。效果如下:


话不多说,开始贴代码

1、attrs。这是自定义view必须的。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="charging_progress">
        <!--item个数-->
        <attr name="cgv_item_count" format="integer" />
        <!--方向-->
        <attr name="cgv_oritation" format="integer" />
        <!--动画时长-->
        <attr name="cgv_duration" format="integer" />
        <!--边界宽度-->
        <attr name="cgv_border_width" format="dimension" />
        <!--边界颜色-->
        <attr name="cgv_border_color" format="color" />
        <!--圆角半径-->
        <attr name="cgv_border_cornor_radius" format="dimension" />
        <!--充电内模块的宽度-->
        <attr name="cgv_item_width" format="dimension" />
        <!--充电内模块的高度-->
        <attr name="cgv_item_height" format="dimension" />
        <!--充电内模块的前景色,充电中的颜色-->
        <attr name="cgv_item_charging_src" format="color" />
        <!--充电内模块的背景色,未充电的颜色-->
        <attr name="cgv_item_charging_background" format="color" />
        <!--view 的背景-->
        <attr name="cgv_background" format="color" />
    </declare-styleable>
</resources>
2、在xml进行引用
<com.example.batteryanim.ChargingProgess
    android:id="@+id/chargingprigressView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:cgv_item_count="1000"
    app:cgv_item_height="0.2dp"
    app:cgv_item_width="100dp"
    app:cgv_item_charging_src="#00A1BD"
    app:cgv_item_charging_background="#000000"
    app:cgv_background="#F9F9F9"
    app:cgv_border_width="4dp"
    app:cgv_border_color="#00A1BD"/>
/>
3、最重要的一个就是自定义这个view
package com.example.batteryanim;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * 充电进度绘制,使用属性动画完成。
 */
public class ChargingProgess extends View {

    private Context mContext;
    private Paint mPaint;//外部矩形以及内部充电动画画笔
    private Paint mPaintTop;//顶部矩形
    private static final int VERTICAL = 0;//竖直方向
    private int oritation;//view的方向
    private float border_width;//边界宽度
    private int item_count;//item个数
    private float item_width;//item宽度
    private float item_height;//item高度
    private int item_charging_src;//view内部的进度前景色
    private int item_charging_background;//view内部的进度背景色
    private int background;//view背景色
    private int border_color; //边界颜色
    private float border_cornor_radius; //圆角半径
    private int duration;//动画时间
    private int mWidth;//整个view的宽度
    private int mHeight;//整个view的高度
    public static final int AC = 2;
    private int chargeType = AC;//充电类型,默认为交流
    private int progress = 0;
    private ValueAnimator animAC;
    private int mCurrPro = 0;
    private int mTopRectHigh;//顶部进度条的高度
    private int mRect = 50;
    private int mWidthRate = 20;

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

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

    public ChargingProgess(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        getSettingValue(attrs);
        initView(context);
    }

    /**
     * 获取在xml中设置的属性值
     *
     * @param attrs
     */
    private void getSettingValue(AttributeSet attrs) {
        TypedArray array = mContext.obtainStyledAttributes(attrs, com.example.batteryanim.R.styleable.charging_progress);
        oritation = array.getInt(com.example.batteryanim.R.styleable.charging_progress_cgv_oritation, VERTICAL);
        border_width = array.getDimension(com.example.batteryanim.R.styleable.charging_progress_cgv_border_width, dp2px(2));
        item_height = array.getDimension(com.example.batteryanim.R.styleable.charging_progress_cgv_item_height, dp2px(10));
        item_width = array.getDimension(com.example.batteryanim.R.styleable.charging_progress_cgv_item_width, dp2px(20));
        item_charging_src = array.getColor(com.example.batteryanim.R.styleable.charging_progress_cgv_item_charging_src, 0xffffea00);
        item_charging_background = array.getColor(com.example.batteryanim.R.styleable.charging_progress_cgv_item_charging_background, 0xff544645);
        background = array.getColor(com.example.batteryanim.R.styleable.charging_progress_cgv_background, 0xff463938);
        border_color = array.getColor(com.example.batteryanim.R.styleable.charging_progress_cgv_border_color, 0xffb49d7c);
        border_cornor_radius = array.getDimension(com.example.batteryanim.R.styleable.charging_progress_cgv_border_cornor_radius, dp2px(2));
        duration = array.getInt(com.example.batteryanim.R.styleable.charging_progress_cgv_duration, 10 * 1000);
        item_count = array.getInt(com.example.batteryanim.R.styleable.charging_progress_cgv_item_count, 100);
    }

    /**
     * 初始化两种画笔
     * @param context
     */
    private void initView(Context context) {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(border_width);
        mPaint.setColor((border_color));

        mPaintTop = new Paint();
        mPaintTop.setStyle(Paint.Style.FILL);
        mPaintTop.setStrokeWidth(border_width);
        mPaintTop.setColor(border_color);
    }

    /**
     * 当前进度
     * @return
     */
    public int getProgress() {
        return progress % 100;
    }

    /**
     * 设置充电进度
     * @param progress
     */
    public void setProgress(int progress) {
        this.progress = progress;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //顶部矩形的宽高
        int left = mWidth * 3 / 8;
        int top = 0;
        int right = 5 * mWidth / 8;
        int bottom = (int) (item_height *60);
        mTopRectHigh = bottom - top;

        //顶部的矩形
        RectF topRect = new RectF(left, top, right, bottom);
        canvas.drawRoundRect(topRect, border_cornor_radius, border_cornor_radius, mPaintTop);

        //大矩形。宽高分别是指最大view的宽高
        RectF border = new RectF(0 + 5, bottom + 5, mWidth - 5, mHeight - 5);
        canvas.drawRoundRect(border, mRect, mRect, mPaint);
        drawACAnimaiton(canvas);

        //因为每次刷新都要走onDraw方法,所以之前在drawACAnimaiton设置了画笔,现在要还原
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(border_width);
        mPaint.setColor((border_color));
    }

    /**
     * 关闭动画
     */
    public void closeAnimation() {
        progress = 0;
        invalidate();
        if (animAC != null) {
            animAC.cancel();
        }
    }

    /**
     * 设置交流动画,属性动画
     */
    public void setACAnimation() {
        chargeType = AC;
        animAC = ValueAnimator.ofInt(0, 1000);
        animAC.setDuration(10000);
        animAC.setInterpolator(new LinearInterpolator());
        animAC.setRepeatCount(ValueAnimator.INFINITE);
        animAC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurrPro = (Integer) animation.getAnimatedValue();
                Log.i("liwei", "mCurrPro:" + mCurrPro);
                invalidate();
            }
        });
        animAC.start();
    }


    /**
     * 绘制交流动画的具体走向
     * @param canvas
     */
    private void drawACAnimaiton(Canvas canvas) {
        RectF backRect = null;
        //设置从30到970是因为顶部一些地方和底部一些距离要留空白
        for (int i = 30; i <= mCurrPro && i <= 970; i++) {
            //这里的宽并没有严格按照比例来,而是自己看界面随意调的,mWidthRate也就没有什么含义
            float left = mWidth / (mWidthRate + 2) + mWidth * 1 / 50;
            //将View里面最下面的矩形是分为1000份的
            float top = mHeight - i * item_height;
            float right = (mWidthRate + 1) * mWidth / (mWidthRate + 2) - mWidth * 1 / 50;
            float bottom = top + item_height;

            //这是为顶部和底部的动画准备的,顶部和底部的动画样子和中间部分不同
            int bottomDis=60;
            int topDis=940;
            int timeRate=1;

            //最底部动画样子
            if (i<bottomDis){
                //动画呈现线性
               int j=bottomDis-i;
                //这里的宽度和中间部分不同
                 left = mWidth / (mWidthRate + 2) + mWidth * 1 / 50+j*timeRate;
                 right = (mWidthRate + 1) * mWidth / (mWidthRate + 2) - mWidth * 1 / 50-j*timeRate;
                backRect = new RectF(left, top, right, bottom);
                mPaint.setStyle(Paint.Style.FILL);
                mPaint.setColor(item_charging_src);
                canvas.drawRect(backRect, mPaint);
            }else if (i>topDis){
                //最顶部动画样子
                //这里的宽度和中间部分不同
                //动画呈现线性
                int j=i-topDis;
                left = mWidth / (mWidthRate + 2) + mWidth * 1 / 50+j*timeRate;
                right = (mWidthRate + 1) * mWidth / (mWidthRate + 2) - mWidth * 1 / 50-j*timeRate;
                backRect = new RectF(left, top, right, bottom);
                mPaint.setStyle(Paint.Style.FILL);
                mPaint.setColor(item_charging_src);
                canvas.drawRect(backRect, mPaint);
            }else if (i==200||i==400||i==600||i==800){
                //这边的判断是为了中间动画的空白
                backRect = new RectF(left, top, right, bottom);
                mPaint.setStyle(Paint.Style.FILL);
                mPaint.setColor(Color.WHITE);
                canvas.drawRect(backRect, mPaint);
            } else{
                //中间动画
                backRect = new RectF(left, top, right, bottom);
                mPaint.setStyle(Paint.Style.FILL);
                mPaint.setColor(item_charging_src);
                canvas.drawRect(backRect, mPaint);
            }
        }
    }

    /**
     * 测量view的宽和高
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //高度等于中间的矩形高度+最顶部的一个小矩形
        mHeight = (int) (item_count * item_height + item_height * 60);
        Log.i("liwei", "mHeight:" + mHeight);
        mWidth = (int) ((mWidthRate + 2) * item_width / mWidthRate);
        setMeasuredDimension(mWidth, mHeight);
    }

    /**
     * dp转化为px`
     *
     * @param dp
     * @return
     */
    protected int dp2px(int dp) {
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                dp,
                getResources().getDisplayMetrics());
    }

    /**
     * sp转为px
     *
     * @param sp
     * @return
     */
    protected int sp2px(int sp) {
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP,
                sp,
                getResources().getDisplayMetrics());
    }
}
项目下载链接在这里,有建议的也可以在评论里告诉我
http://download.youkuaiyun.com/download/qq_25330791/10042581
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值