如图所示:

自定义属性:

在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. node开发遇到类似:Error: ENOENT: no such file or directory, scandir 'D:\work\taro-components- ....... _node-sass@4.12.0@node-sass\vendor

    唯一的有参考价值的文章,https://www.cnblogs.com/milo-wjh/p/9175138.html 我可以负责任的说,以下的方法, npm rebuild node-sass 80 ...

  2. Android 开发基础入门篇: 动态权限申请

    说明: 咱们在安装APP的时候经常会看到,类似于下面的提示 goolge为了保护用户隐私,在android 6.0开始,某些隐私权限,必须用户允许以后,内部程序方可使用 这就涉及到权限动态申请问题. ...

  3. Pandas之csv文件对列行的相关操作

    1.Pandas对数据某一列删除 1.删除列 import pandas as pd df = pd.read_csv(file) #axis=1就是删除列 df.drop(['列名1','列名2'] ...

  4. Codeforces Round 563 (Div. 2) 题解

    自己开了场镜像玩. 前三题大水题.D有点意思.E完全不会.F被题意杀了……然而还是不会. 不过看过(且看懂)了官方题解,所以这里是六题题解齐全的. A 水题.给原序列排序,如果此时合法则直接输出,否则 ...

  5. Java的策略和保护域

    参考文章: (1)java之jvm学习笔记十(策略和保护域) https://blog.csdn.net/yfqnihao/article/details/8271415

  6. Leetcode 1262. 可被三整除的最大和

    题目:给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和. 示例 1: 输入:nums = [3,6,5,1,8] 输出:18 解释:选出数字 3, 6, 1 和 8,它们的和是 18( ...

  7. git强制推送命令

    git push -f origin master 注释: origin远程仓库名,master分支名,-f为force,意为:强行.强制. 这行命令的意思就是强制用本地的代码去覆盖掉远程仓库的代码, ...

  8. sql server数据表大小初始化

    sql server表在存储大数据和处理大数据表时,经常会遇到表空间越来越大,有时候会超出应该占有空间大小很多,此时如果表数据是压缩存储的,那么重新执行一下压缩脚本,数据的大小会重新初始化,然后再使用 ...

  9. oracle 之 using 使用

    oracle  中 using关键字使用规则: 1.查询必须是等值连接.2.等值连接中的列必须具有相同的名称和数据类型. 使用using关键字简化连接时,需要注意以下几点:1.使用 table1表和 ...

  10. 第十节:Asp.Net Core 配置详解和选项模式

    一. 各种文件的读取 1.说明 在.Net Core中,各种配置文件的读取都需要依赖[Microsoft.Extensions.Configuration]程序集,当然在Asp.Net Core中已经 ...