Android中自定义水球

如图所示:

自定义属性:

在values下创建attrs.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="WaveProgressView">
        <attr name="radius" format="dimension|reference" />
        <attr name="radius_color" format="color|reference" />
        <attr name="progress_text_color" format="color|reference" />
        <attr name="progress_text_size" format="dimension|reference" />
        <attr name="progress_color" format="color|reference" />
        <attr name="progress" format="float" />
        <attr name="maxProgress" format="float" />
    </declare-styleable>


</resources>

 样式 styles.xml 中

<style name="WaveProgressViewDefault">
        <item name="radius">55dp</item>
        <item name="progress_text_color">#fff</item>
        <item name="progress_text_size">20sp</item>
        <item name="progress_color">#C215AB30</item>
        <item name="radius_color">#FF734B58</item>
        <item name="progress">0</item>
        <item name="maxProgress">100</item>
    </style>

自定义view

package com.chuanye.shuiqiudemo1;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import java.text.DecimalFormat;

public class WaveProgressView extends View {

    private int radius = dp2px(55);//半径
    private int textColor;//进度字体颜色
    private int textSize;//进度字体大小
    private int progressColor;//进度颜色
    private int radiusColor;
    private Paint textPaint;
    private Paint circlePaint;
    private Paint pathPaint;
    private Bitmap bitmap;
    private Canvas bitmapCanvas;
    private int width = 10, height = 10;
    private int minPadding;
    private float progress;//当前进度
    private float maxProgress;//最大进度
    private Path path = new Path();
    private DecimalFormat df = new DecimalFormat("0.0");


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

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

    public WaveProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WaveProgressView, defStyleAttr, R.style.WaveProgressViewDefault);
        radius = (int) a.getDimension(R.styleable.WaveProgressView_radius, radius);//半径
        textColor = a.getColor(R.styleable.WaveProgressView_progress_text_color, 0);//进度字体颜色
        textSize = a.getDimensionPixelSize(R.styleable.WaveProgressView_progress_text_size, 0);//进度字体大小
        progressColor = a.getColor(R.styleable.WaveProgressView_progress_color, 0);//进度颜色
        radiusColor = a.getColor(R.styleable.WaveProgressView_radius_color, 0);//半径颜色
        progress = a.getFloat(R.styleable.WaveProgressView_progress, 0);//当前进度
        maxProgress = a.getFloat(R.styleable.WaveProgressView_maxProgress, 100);//最大进度
        a.recycle();//回收利用

        //初始化一些画笔  文本画笔
        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(textSize);
        textPaint.setColor(textColor);
        textPaint.setDither(true);


        //圆 画笔
        circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setColor(radiusColor);
        circlePaint.setDither(true);

        //道路 进度画笔
        pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        pathPaint.setColor(progressColor);
        pathPaint.setDither(true);
        //设置转送模式
        pathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //计算宽和高
        int exceptW = getPaddingLeft() + getPaddingRight() + 2 * radius;
        int exceptH = getPaddingTop() + getPaddingBottom() + 2 * radius;
        int width = resolveSize(exceptW, widthMeasureSpec);
        int height = resolveSize(exceptH, heightMeasureSpec);
        int min = Math.min(width, height);

        this.width = this.height = min;

        //计算半径,减去padding的最小值
        int minLR = Math.min(getPaddingLeft(), getPaddingRight());
        int minTB = Math.min(getPaddingTop(), getPaddingBottom());
        minPadding = Math.min(minLR, minTB);
        radius = (min - minPadding * 2) / 2;

        setMeasuredDimension(min, min);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888);
            bitmapCanvas = new Canvas(bitmap);
        }
        bitmapCanvas.save();
        //移动坐标系   转化画布
        bitmapCanvas.translate(minPadding, minPadding);
        //绘制圆
        bitmapCanvas.drawCircle(radius, radius, radius, circlePaint);

        //绘制PATH
        //重置绘制路线
        path.reset();
        float percent = progress * 1.0f / maxProgress;
        float y = (1 - percent) * radius * 2;
        //移动到右上边
        path.moveTo(radius * 2, y);
        //移动到最右下方
        path.lineTo(radius * 2, radius * 2);
        //移动到最左下边
        path.lineTo(0, radius * 2);
        //移动到左上边
        // path.lineTo(0, y);
        //实现左右波动,根据progress来平移
        path.lineTo(-(1 - percent) * radius * 2, y);
        if (progress != 0.0f) {
            //根据直径计算绘制贝赛尔曲线的次数
            int count = radius * 4 / 60;
            //控制-控制点y的坐标
            float point = (1 - percent) * 15;
            for (int i = 0; i < count; i++) {
                path.rQuadTo(15, -point, 30, 0);
                path.rQuadTo(15, point, 30, 0);
            }
        }
        //闭合
        path.close();
        bitmapCanvas.drawPath(path, pathPaint);

        //绘制文字
        String text = progress + "%";
        float textW = textPaint.measureText(text);
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float baseLine = radius - (fontMetrics.ascent + fontMetrics.descent) / 2;
        bitmapCanvas.drawText(text, radius - textW / 2, baseLine, textPaint);

        bitmapCanvas.restore();

        canvas.drawBitmap(bitmap, 0, 0, null);
    }

    public float getProgress() {
        return progress;
    }

    public void setProgress(float progress) {
        this.progress = Float.valueOf(df.format(progress));
        invalidate();
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }


    private final static class SavedState extends BaseSavedState {
        float progress;

        public SavedState(Parcel source) {
            super(source);
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.progress = progress;
        return ss;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        setProgress(ss.progress);
    }

}

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:wpv="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_main3"
        android:text="开启"
        android:onClick="start"
        tools:ignore="OnClick" />


    <com.chuanye.shuiqiudemo1.WaveProgressView
        android:id="@+id/wpv_0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        wpv:progress="15" />

    <com.chuanye.shuiqiudemo1.WaveProgressView
        android:id="@+id/wpv_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        wpv:maxProgress="80"
        wpv:progress_color="#dd65A6DA"
        wpv:progress_text_color="@color/colorAccent"
        wpv:progress_text_size="20sp"
        wpv:radius="60dp"
        wpv:radius_color="#AAffdd33" />

    <com.chuanye.shuiqiudemo1.WaveProgressView
        android:id="@+id/wpv_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        wpv:maxProgress="120"
        wpv:progress_color="#DC7E2040"
        wpv:progress_text_size="13sp"
        wpv:radius="70dp"
        wpv:radius_color="#7F6B1AB3" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_main32"
        android:text="设置值" />
</LinearLayout>

MainActivity 中

package com.chuanye.shuiqiudemo1;

import android.animation.ObjectAnimator;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Button;

public class Main3Activity extends AppCompatActivity {
    //https://blog.csdn.net/ta893115871/article/details/52245815/
    //private WaveProgressView waveProgressView_0;
    private String TAG = "Main3Activity";
    //private WaveProgressView waveProgressView_1;
    //private WaveProgressView waveProgressView_2;
    private WaveProgressView waveProgressView_0, waveProgressView_1, waveProgressView_2;

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

        Log.i(TAG,"onCreate...");

        waveProgressView_0 = (WaveProgressView) findViewById(R.id.wpv_0);

        waveProgressView_1 = (WaveProgressView) findViewById(R.id.wpv_1);
        waveProgressView_2 = (WaveProgressView) findViewById(R.id.wpv_2);

        

        Button btn_main32 = findViewById(R.id.btn_main32);
        btn_main32.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                waveProgressView_0.setProgress(85);
            }
        });


    }


    public void start(View view) {
        ObjectAnimator objectAnimator0 = ObjectAnimator.ofFloat(waveProgressView_0, "progress", 0f, 100f);
        objectAnimator0.setDuration(3300);
        objectAnimator0.setInterpolator(new LinearInterpolator());
        objectAnimator0.start();

        ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(waveProgressView_1, "progress", 0f, 80f);
        objectAnimator1.setDuration(3000);
        objectAnimator1.setInterpolator(new AccelerateInterpolator());
        objectAnimator1.start();

        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(waveProgressView_2, "progress", 0f, 120f);
        objectAnimator2.setDuration(5000);
        objectAnimator2.setInterpolator(new BounceInterpolator());
        objectAnimator2.start();
    }
}

完成

posted on 2019-05-16 15:14  巫山老妖  阅读(520)  评论(0编辑  收藏  举报