安卓开发之自定义动画控件BatteryView(电池加载动画)

前几天在网页上看到一个不错的加载动画View后,想将它在安卓上实现一遍。效果如下,很简单。

安卓开发之自定义动画控件BatteryView(电池加载动画)_第1张图片

因为控件实现动画时,更新视图的频率会很高。为了减少内存的占用,决定使用SurfaceView来实现。

一、对控件的测量

使用的规则是:当控件的宽/高不是固定时,宽/高的大小为默认的宽高+padding值。反之,使用传递过来的宽高。

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

    int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
    int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
    int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
    int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

    if(modeWidth == MeasureSpec.AT_MOST || modeWidth == MeasureSpec.UNSPECIFIED ){
        sizeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,bwidth,getContext().getResources().getDisplayMetrics());
        sizeWidth += getPaddingLeft()+getPaddingRight();
    }
    if(modeHeight == MeasureSpec.AT_MOST || modeHeight == MeasureSpec.UNSPECIFIED ){
        sizeHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,bheight,getContext().getResources().getDisplayMetrics());
        sizeHeight += getPaddingBottom()+getPaddingTop();
    }

    setMeasuredDimension(sizeWidth,sizeHeight);

}

二、对控件的绘制

private void drawView(Canvas canvas){

    // 绘制背景图
    canvas.drawColor(backgroundColor);

    // 绘制电池框
    canvas.drawRoundRect(SrectF,bRadius,bRadius,paintS);

    // 绘制电池的小点
    canvas.drawRect(centerX+bwidth/2-distance,centerY-bheight/4,centerX+bwidth/2,centerY+bheight/4,paintF);

    // 更新电池填充的右边大小
    FrectF.right =  FrectF.left+varyInnerWidth;

    // 绘制电池的填充
    canvas.drawRoundRect(FrectF,bRadius,bRadius,paintF);

    // 根据不同情况,修改电池填充的右边大小
    if(SrectF.left+varyInnerWidth>centerX+bwidth/2-distance*2){
        // 超过范围时
        varyInnerWidth = centerX+bwidth/2-distance*2;
    }else if(SrectF.left+varyInnerWidth==centerX+bwidth/2-distance*2){
        // 等于范围时:
        varyInnerWidth = 0;
    }else {
        // 增长时:
        varyInnerWidth +=2;
    }


}

三、异步更新控件视图

@Override
public void run() {
    while (isThreadRunning) {
        // 获取视图,锁定视图
        canvas = surfaceHolder.lockCanvas();
        if(canvas!=null){
            drawView(canvas);
            // 更新视图
            surfaceHolder.unlockCanvasAndPost(canvas);
        }
        try {
            Thread.sleep(40); // 相当于帧频,数值越小画面就越流畅
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

四、自定义控件属性

只提取了一些简单的属性。


    
    
    
    
    

五、完整BatteryView代码

package com.cxmscb.cxm.videosplash;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by cxm on 2016/9/22.
 */
public class BatteryView extends SurfaceView implements SurfaceHolder.Callback,Runnable{

    private Paint paintS,paintF;
    private int bwidth;
    private int bheight;
    int varyInnerWidth;
    private int bColor,backgroundColor;
    private float bRadius;
    private RectF SrectF,FrectF;
    private Thread thread;
    private SurfaceHolder surfaceHolder;
    private Canvas canvas;
    private boolean isThreadRunning = true;
    private int distance;
    private int centerX,centerY;

    public BatteryView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

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

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

    private void init(AttributeSet attrs) {
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
        SrectF = new RectF();
        FrectF = new RectF();
        distance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,4,getContext().getResources().getDisplayMetrics());

        TypedArray attrArray = getContext().obtainStyledAttributes(attrs, R.styleable.BatteryLoadingView);
        if (attrArray != null) {

            bwidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,80,getContext().getResources().getDisplayMetrics());
            bheight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,30,getContext().getResources().getDisplayMetrics());

            bwidth = attrArray.getDimensionPixelSize(R.styleable.BatteryLoadingView_outBWidth, bwidth);
            bheight = attrArray.getDimensionPixelSize(R.styleable.BatteryLoadingView_outBHeight, bheight);
            bColor = attrArray.getColor(R.styleable.BatteryLoadingView_bColor,Color.GREEN);
            backgroundColor = attrArray.getColor(R.styleable.BatteryLoadingView_backgroundColor,Color.WHITE);
            bRadius = attrArray.getFloat(R.styleable.BatteryLoadingView_bRadius,9f);
            attrArray.recycle();
        }
        initPaint();


    }

    private void initPaint() {
        paintS = new Paint();
        paintF = new Paint();
        paintS.setColor(bColor);
        paintF.setColor(bColor);
        paintS.setStyle(Paint.Style.STROKE);
        paintS.setStrokeWidth(6);
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new Thread(this);
        thread.start();
        isThreadRunning = true;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        varyInnerWidth = 0;

        centerX = getMeasuredWidth()/2;
        centerY = getMeasuredHeight()/2 ;

        SrectF.left = centerX-bwidth/2 ;
        SrectF.top = centerY-bheight/2;
        SrectF.right =  centerX+bwidth/2-distance*2;
        SrectF.bottom = centerY+bheight/2;

        FrectF.left = SrectF.left ;
        FrectF.top = SrectF.top;
        FrectF.right =  SrectF.left;
        FrectF.bottom = SrectF.bottom;

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isThreadRunning = false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        if(modeWidth == MeasureSpec.AT_MOST || modeWidth == MeasureSpec.UNSPECIFIED ){
            sizeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,bwidth,getContext().getResources().getDisplayMetrics());
            sizeWidth += getPaddingLeft()+getPaddingRight();
        }
        if(modeHeight == MeasureSpec.AT_MOST || modeHeight == MeasureSpec.UNSPECIFIED ){
            sizeHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,bheight,getContext().getResources().getDisplayMetrics());
            sizeHeight += getPaddingBottom()+getPaddingTop();
        }

        setMeasuredDimension(sizeWidth,sizeHeight);

    }


    private void drawView(Canvas canvas){

        canvas.drawColor(backgroundColor);

        canvas.drawRoundRect(SrectF,bRadius,bRadius,paintS);

        canvas.drawRect(centerX+bwidth/2-distance,centerY-bheight/4,centerX+bwidth/2,centerY+bheight/4,paintF);

        FrectF.right =  FrectF.left+varyInnerWidth;

        canvas.drawRoundRect(FrectF,bRadius,bRadius,paintF);


        if(SrectF.left+varyInnerWidth>centerX+bwidth/2-distance*2){
            varyInnerWidth = centerX+bwidth/2-distance*2;
        }else if(SrectF.left+varyInnerWidth==centerX+bwidth/2-distance*2){
            varyInnerWidth = 0;
        }else {
            varyInnerWidth +=2;
        }


    }


    @Override
    public void run() {
        while (isThreadRunning) {
            canvas = surfaceHolder.lockCanvas();
            if(canvas!=null){
                drawView(canvas);
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
            try {
                Thread.sleep(40); // 相当于帧频了,数值越小画面就越流畅
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

}

效果图Demo : Github

你可能感兴趣的:(Android学习)