android之二次水波纹控件

这段时间项目做完了,也没什么事情,本以为可以偷懒一段时间,结果老总接了一个车载项目让我做,心碎,没做过,很慌,经过各方打听,发现车载和手机app开发的流程基本一致,瞬间就淡定了,那就开始搞

项目开始就知道会有各种自定义控件,今天是第一天,搞了一个水波纹的自定义控件,先看效果
这里写图片描述

第一眼还是觉得可以看的,其实我觉得有点丑,ui妹子说挺好看,好吧,那就这样吧
这里面难点主要是波纹这个了,这个我也是借用了一个开源项目的代码
其他的都很简单,代码如下

package com.example.zhu.demo333.featrue.widget;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;


/**
 * Created by mou on 2017/8/23.
 */

public class WaveLoadingView extends View {

    private static final float DEFAULT_AMPLITUDE_RATIO = 0.1f;
    private static final float DEFAULT_AMPLITUDE_VALUE = 20.0f;
    private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f;
    private static final float DEFAULT_WAVE_LENGTH_RATIO = 1.0f;
    //默认的进度
    private static final int DEFAULT_WAVE_PROGRESS_VALUE = 100;
    //默认波纹颜色
    private static final int DEFAULT_WAVE_COLOR = Color.parseColor("#456cda");
    //默认背景颜色
    private static final int DEFAULT_WAVE_BACKGROUND_COLOR = Color.parseColor("#000000");
    //默认文字的颜色
    private static final int DEFAULT_TITLE_COLOR = Color.WHITE;
    //上面文字的大小
    private static final float DEFAULT_TITLE_TOP_SIZE = 16.0f;
    //下面文字的大小
    private static final float DEFAULT_TITLE_CENTER_SIZE = 18.0f;
    //半径
    private float radius;
    //波浪的高度
    private float mAmplitudeRatio = DEFAULT_AMPLITUDE_VALUE / 1000;
    //波纹的颜色
    private int mWaveColor = DEFAULT_WAVE_COLOR;
    //上面的文字
    private static final String TOP_TITLE = "本月可用流量";
    //下面的文字
    private String mCenterTitle = "0.0GB";
    private float mDefaultWaterLevel;
    private float mWaterLevelRatio = 1f;
    private float mWaveShiftRatio = 0f;
    private int mProgressValue = DEFAULT_WAVE_PROGRESS_VALUE;
    private BitmapShader mWaveShader;
    // 渐变矩阵
    private Matrix mShaderMatrix;
    //画波浪
    private Paint mWavePaint;
    //画背景
    private Paint mWaveBgPaint;
    // 上面文字的画笔
    private Paint mTopTitlePaint;
    //下面文字的画笔
    private Paint mCenterTitlePaint;
    //画背景
    private Paint paintCircleBg;
    //画小球的画笔
    private Paint mPaintBall;
    //外边缘的进度条
    private Paint paintProgressOut;
    //波浪动画
    private ObjectAnimator waveShiftAnim;
    private AnimatorSet mAnimatorSet;
    //开始角度
    private float startangle = 180f;


    public WaveLoadingView(final Context context) {
        this(context, null);
    }

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

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

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        initAnimation();
        mShaderMatrix = new Matrix();

        mWavePaint = new Paint();
        mWavePaint.setAntiAlias(true);
        mWaveBgPaint = new Paint();
        mWaveBgPaint.setAntiAlias(true);
        mWaveBgPaint.setColor(DEFAULT_WAVE_BACKGROUND_COLOR);

        mTopTitlePaint = new Paint();
        mTopTitlePaint.setColor(DEFAULT_TITLE_COLOR);
        mTopTitlePaint.setStyle(Paint.Style.FILL);
        mTopTitlePaint.setAntiAlias(true);
        mTopTitlePaint.setTextSize(sp2px(DEFAULT_TITLE_TOP_SIZE));

        mCenterTitlePaint = new Paint();
        mCenterTitlePaint.setColor(DEFAULT_TITLE_COLOR);
        mCenterTitlePaint.setStyle(Paint.Style.FILL);
        mCenterTitlePaint.setAntiAlias(true);
        mCenterTitlePaint.setTextSize(sp2px(DEFAULT_TITLE_CENTER_SIZE));
        Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
        mCenterTitlePaint.setTypeface(font);

        paintCircleBg = new Paint();
        paintCircleBg.setStyle(Paint.Style.FILL);
        paintCircleBg.setAntiAlias(true);
        paintCircleBg.setColor(Color.BLACK);

        paintProgressOut = new Paint();
        paintProgressOut.setStyle(Paint.Style.STROKE);
        paintProgressOut.setAntiAlias(true);
        paintProgressOut.setColor(Color.parseColor("#446eb5dd"));
        paintProgressOut.setStrokeWidth(sp2px(3));
        paintProgressOut.setStrokeCap(Paint.Cap.ROUND);

        mPaintBall = new Paint();
        mPaintBall.setStyle(Paint.Style.FILL);
        mPaintBall.setAntiAlias(true);
        mPaintBall.setColor(Color.parseColor("#bb45DAB9"));
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (mWaveShader != null) {
            if (mWavePaint.getShader() == null) {
                mWavePaint.setShader(mWaveShader);
            }
            mShaderMatrix.setScale(1, mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO, 0, mDefaultWaterLevel);
            mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(),
                    (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
            mWaveShader.setLocalMatrix(mShaderMatrix);     // Assign matrix to invalidate the shader.
            drawCircle(canvas);
        } else {
            mWavePaint.setShader(null);
        }
        //画上面的文字
        drawTopText(canvas);
        //画中间的文字
        drawCenterText(canvas);
    }


    private void drawCircle(Canvas canvas) {
        radius = getWidth() / 2f;

        paintCircleBg.setColor(Color.BLACK);
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius - dp2px(30), paintCircleBg);

        paintCircleBg.setColor(Color.parseColor("#44000000"));
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius - dp2px(20), paintCircleBg);

        //画背景
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius - dp2px(40), mWaveBgPaint);
        //画波浪
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius - dp2px(40), mWavePaint);
        //画进度圆弧
        int percent = mProgressValue * (360) / DEFAULT_WAVE_PROGRESS_VALUE;
        RectF bgRectf = new RectF(getPaddingLeft() + dp2px(10), getPaddingTop() + dp2px(10),
                getMeasuredWidth() - dp2px(10), getMeasuredHeight() - dp2px(10));
        canvas.drawArc(bgRectf, startangle, -percent, false, paintProgressOut);//percent的正负表示顺时针和逆时针

        //画小球
        canvas.save();
        canvas.translate(getWidth() / 2, getHeight() / 2);
        canvas.rotate(-percent);
        canvas.drawCircle(-(radius - dp2px(10)), 0, dp2px(5), mPaintBall);
        canvas.rotate(percent);
        canvas.restore();
    }


    private void drawCenterText(Canvas canvas) {
        if (!TextUtils.isEmpty(mCenterTitle)) {
            float middle = mCenterTitlePaint.measureText(mCenterTitle);
            canvas.drawText(mCenterTitle, (getWidth() - middle) / 2,
                    getHeight()/2 + dp2px(30), mCenterTitlePaint);
        }
    }

    private void drawTopText(Canvas canvas) {
        if (!TextUtils.isEmpty(TOP_TITLE)) {
            float top = mTopTitlePaint.measureText(TOP_TITLE);
            canvas.drawText(TOP_TITLE, (getWidth() - top) / 2, getHeight() / 2, mTopTitlePaint);
        }
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        updateWaveShader();
    }

    /**
     *
     */
    private void updateWaveShader() {
        // IllegalArgumentException: width and height must be > 0 while loading Bitmap from View
        // http://stackoverflow.com/questions/17605662/illegalargumentexception-width-and-height-must-be-0-while-loading-bitmap-from

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        if (width > 0 && height > 0) {
            double defaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / width;
            float defaultAmplitude = height * DEFAULT_AMPLITUDE_RATIO;
            mDefaultWaterLevel = height * DEFAULT_WATER_LEVEL_RATIO;
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            Paint wavePaint = new Paint();
            wavePaint.setStrokeWidth(2);
            wavePaint.setAntiAlias(true);

            // Draw default waves into the bitmap.
            // y=Asin(ωx+φ)+h
            final int endX = width + 1;
            final int endY = height + 1;

            float[] waveY = new float[endX];

            wavePaint.setColor(adjustAlpha(mWaveColor, 0.3f));
            for (int beginX = 0; beginX < endX; beginX++) {
                double wx = beginX * defaultAngularFrequency;
                float beginY = (float) (mDefaultWaterLevel + defaultAmplitude * Math.sin(wx));
                canvas.drawLine(beginX, beginY, beginX, endY, wavePaint);
                waveY[beginX] = beginY;
            }
            wavePaint.setColor(mWaveColor);
            final int wave2Shift = (int) (width / 4);
            for (int beginX = 0; beginX < endX; beginX++) {
                canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
            }
            mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
            this.mWavePaint.setShader(mWaveShader);
        }
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        int imageSize = (width < height) ? width : height;
        setMeasuredDimension(imageSize, imageSize);

    }

    /**
     * 测量宽度
     */
    private int measureWidth(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else {
            result = specSize;
        }
        return result;
    }

    /**
     * 测量高度
     */
    private int measureHeight(int measureSpecHeight) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpecHeight);
        int specSize = MeasureSpec.getSize(measureSpecHeight);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else {
            result = specSize;
        }
        return (result + 2);
    }


    /**
     * 设置进度
     */
    public void setProgressValue(int progress) {
        mProgressValue = progress;
        ObjectAnimator waterLevelAnim = ObjectAnimator.ofFloat(this, "waterLevelRatio", mWaterLevelRatio, (mProgressValue * 1f / 100));
        if (progress > 50) {
            waterLevelAnim.setDuration(800);
        } else {
            waterLevelAnim.setDuration(1200);
        }
//        waterLevelAnim.setInterpolator(new DecelerateInterpolator());
        AnimatorSet animatorSetProgress = new AnimatorSet();
        animatorSetProgress.play(waterLevelAnim);
        animatorSetProgress.start();
    }


    public void setWaveShiftRatio(float waveShiftRatio) {
        if (this.mWaveShiftRatio != waveShiftRatio) {
            this.mWaveShiftRatio = waveShiftRatio;
            invalidate();
        }
    }

    public float getWaveShiftRatio() {
        return mWaveShiftRatio;
    }

    public void setWaterLevelRatio(float waterLevelRatio) {
        if (this.mWaterLevelRatio != waterLevelRatio) {
            this.mWaterLevelRatio = waterLevelRatio;
            invalidate();
        }
    }


    public void setCenterTitle(String centerTitle) {
        mCenterTitle = centerTitle;
        invalidate();
    }

    public void startAnimation() {
        if (mAnimatorSet != null) {
            mAnimatorSet.start();
        }
    }

    public void endAnimation() {
        if (mAnimatorSet != null) {
            mAnimatorSet.end();
        }
    }

    public void cancelAnimation() {
        if (mAnimatorSet != null) {
            mAnimatorSet.cancel();
        }
    }

    private void initAnimation() {
        // Wave waves infinitely.
        waveShiftAnim = ObjectAnimator.ofFloat(this, "waveShiftRatio", 0f, 1f);
        waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
        waveShiftAnim.setDuration(1000);
        waveShiftAnim.setInterpolator(new LinearInterpolator());
        mAnimatorSet = new AnimatorSet();
        mAnimatorSet.play(waveShiftAnim);
    }

    @Override
    protected void onAttachedToWindow() {
        startAnimation();
        super.onAttachedToWindow();
    }

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

    /**
     */
    private int adjustAlpha(int color, float factor) {
        int alpha = Math.round(Color.alpha(color) * factor);
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.argb(alpha, red, green, blue);
    }

    /**
     * Paint.setTextSize(float textSize) default unit is px.
     */
    private int sp2px(float spValue) {
        final float fontScale = getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    private int dp2px(float dp) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

}

猜你喜欢

转载自blog.csdn.net/villa_mou/article/details/78743361