如图所示:

自定义属性:

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

完成

Android中自定义水球的更多相关文章

  1. [转]Android中自定义checkbox样式

    android中自定义checkbox的图片和大小   其实很简单,分三步: 1.在drawable中创建文件checkbox_selector.xml: <?xml version=" ...

  2. 转--Android中自定义字体的实现方法

    1.Android系统默认支持三种字体,分别为:“sans”, “serif”, “monospace 2.在Android中可以引入其他字体 . 复制代码 代码如下: <?xml versio ...

  3. Android中自定义ActionBar的背景色等样式style

    Android中想要去自定义ActionBar的背景色等样式. [折腾过程] 1.自己找代码,发现对应的配置的地方了: AndroidManifest.xml ? 1 2 <applicatio ...

  4. Android中自定义veiw使用Java中的回调方法

    //------------------MainActivity----中---------------------------------- import android.os.Bundle;imp ...

  5. android开发:Android 中自定义View的应用

    大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习惯了Android 传统的页面布局方式,如下代码: <?xml version="1.0&q ...

  6. Android中自定义组合控件

    Android中自定义控件的情况非常多,一般自定义控件可以分为两种:继承控件及组合控件.前者是通过继承View或其子类,重写方法实现自定义的显示及事件处理方式:后者是通过组合已有的控件,来实现结构的简 ...

  7. Android中自定义ListView实现上拉加载更多和下拉刷新

    ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能.这里我就简单记录一下实现过程. 实现这个功能的方法不止一个,Gi ...

  8. Android中自定义View和自定义动画

    Android FrameWork 层给我们提供了很多界面组件,但是在实际的商业开发中这些组件往往并不能完全满足我们的需求,这时候我们就需要自定义我们自己的视图和动画. 我们要重写系统的View就必须 ...

  9. Android中自定义IP控件

    最近在搞Android项目,之前并没有系统的去学过这方面的编程,只能边看书边撸代码.在项目的开发的过程中,需要一个IP控件,后面了解到Android中并没有这样的控件,于是网上搜索,发现得到的结果并不 ...

随机推荐

  1. Java 基本类型、封装类型、常量池、基本运算

    基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768~3 ...

  2. [KCOJ20170214]又一个背包

    题目描述 Description 小W要去军训了!由于军训基地是封闭的,小W在军训期间将无法离开军训基地.所以他没有办法出去买他最爱吃的零食.万般无奈的小W只好事先买好他爱吃的零食,装在背包里带入军训 ...

  3. Java 集合系列之四:Queue基本操作

    1. Java Queue 1. Java Queue 重要观点 Java Queue接口是Java Collections Framework的成员. Queue 实现通常不允许插入 null 元素 ...

  4. Hotspot的Metaspace

    Meta Space是JDK1.8引入的,在JDK1.8使用的是方法区,永久代(Permnament Generation).元空间存储的是元信息,使用的是操作系统的本地内存(Metaspace与Pe ...

  5. 深入理解 JavaScript 中的 class

    在 ES6 规范中,引入了 class 的概念.使得 JS 开发者终于告别了,直接使用原型对象模仿面向对象中的类和类继承时代. 但是JS 中并没有一个真正的 class 原始类型, class 仅仅只 ...

  6. FCB CCB FileObject

    CCB  ContextControlBlock  是存Private信息的,这个FO的特殊信息 FCB  FileControlBlock          是存全局信息的 FO    FileOb ...

  7. 别再说你不会 ElasticSearch 调优了,都给你整理好了

    来源:http://tinyurl.com/y4gnzbje 第一部分:调优索引速度 第二部分-调优搜索速度 第三部分:通用的一些建议 英文原文:https://www.elastic.co/guid ...

  8. Shell脚本之九 输入输出重定向和文件包含

    输出重定向:是指不使用系统提供的标准输入端口来输出,而是重新指定其他来进行输出.例如在终端输入的字符串本来是要输出到终端屏幕上的,但可以将输出指定为其他文件,将输入字符串输出到该文件中,而不再是屏幕上 ...

  9. 爬取'Content-Type': 'text/plain;charset=UTF-8' ,发送请求数据方式

    解决方式 直接以字符串的方式发送data就可以得到响应数据 import requests data = 'k1:v1,k2:v2' requests.post(url, data=data)

  10. 前端与算法 leetcode 36. 有效的数独

    目录 # 前端与算法 leetcode 36. 有效的数独 题目描述 概要 提示 解析 算法 传入[['5', '3', '.', '.', '7', '.', '.', '.', '.'],['6' ...