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(); } }
完成