前言

最近一直在研究自定义view,正好项目中有一个根据下载进度来实现球体进度的需求,所以自己写了个进度球,代码非常简单。先看下效果:

效果还是非常不错的。

准备知识

要实现上面的效果我们只要掌握两个知识点就好了,一个是Handler机制,用于发消息刷新我们的进度球,一个是clipDrawable。网上关于Handler的教程很多,这里重点介绍一下clipDrawable,进度球的实现全靠clipDrawable。

clipDrawable

如下图所示:ClipDrawable和InsertDrawable一样继承DrawableWrapper,DrawableWrapper继承Drawable。

ClipDrawable是可以进行裁剪操作的drawable,提供了函数setLevel(@IntRange(from=0,to=10000) int level)来设置裁剪的大小。level越大图片越大。level=0时图片完全不显示,level=10000时图片完全显示。

ClipDrawable clipDrawable = (ClipDrawable) getContext().getResources().getDrawable(R.drawable.bottom_top_clip_gradient_color);//获取图片

clipDrawable.setLevel(100);//进行裁剪

一般还要设置裁剪的方向,垂直裁剪还是水平裁剪,我们这个进度球用的是垂直从下向上裁剪。

思路:

知道了ClipDrawable的用法,进度球就好实现了。只需要一个球形的图片,从下往上裁剪,通过设置setLevel从0到10000,就可以实现进度球从0到进度100的效果了。

实现

1、定义BallProgress,BallProgress继承View,重写onDraw()方法,用于实现进度球的view。

/**

* Created time 15:02.

*

* @author huhanjun

* @since 2018/12/26

*/

public class BallProgress extends View {

private float mProgress = 0.0f; //取值位 0 - 1.0

private boolean selected = true;

public BallProgress(Context context) {

super(context);

}

public BallProgress(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

public BallProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mProgressPaint = new Paint();//初始化,定义画笔。

mProgressPaint.setAntiAlias(true);//设置抗锯齿

}

public float getProgress() {

return mProgress;

}

public void setProgress(float progress) {//设置进度,通过进度的大小实现裁剪的大小

mProgress = progress;

invalidate();

}

private Paint mProgressPaint;

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

Bitmap dst = getRectangleBitmap();//获取bitmap

setLayerType(LAYER_TYPE_HARDWARE, null); //开启硬件离屏缓存

canvas.drawBitmap(dst, 0, 0, mProgressPaint);

}

private Bitmap getRectangleBitmap() {

int width = getWidth();

int height = getHeight();

Bitmap dstBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

ClipDrawable clipDrawable = null;

clipDrawable = (ClipDrawable) getContext().getResources().getDrawable(R.drawable.bottom_top_clip_single_color);//获取球形的背景图片,用于裁剪,就是上面看到的进度球中的图片

clipDrawable.setBounds(new Rect(0, 0, width, height));//设置边界

clipDrawable.setLevel((int) (10000 * mProgress));//设置进度,

Canvas canvas = new Canvas(dstBitmap);//设置画布

clipDrawable.draw(canvas);//绘制

return dstBitmap;//将bitmap返回

}

}

有了自定义的BallProgress,就可以在布局中使用了,定义的xml文件如下:

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity">

android:id="@+id/progress"

android:layout_width="@dimen/progress_size"

android:layout_height="@dimen/progress_size"

android:layout_centerInParent="true" />

android:layout_width="@dimen/progress_size"

android:layout_height="@dimen/progress_size"

android:layout_centerInParent="true"

android:background="@drawable/main_tab_un_select_bg" />

上面布局中的ImageView是悬浮球的边界。在MainActivity中来定时的改变进度球的大小。代码如下:

public class MainActivity extends AppCompatActivity {

private final int PROGRESS_MESSAGE = 0;

private float progress = 0.0f;

private BallProgress mBallProgress;

private Handler mHandler = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case PROGRESS_MESSAGE:

progress = (progress > 0.9f) ? 0.9f : progress;

mBallProgress.setProgress(progress);//接收消息,改变进度球的进度

break;

}

return true;

}

});

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

initAction();

}

private void initView() {

mBallProgress = findViewById(R.id.progress);

}

//发消息

private void initAction() {

new Thread(new Runnable() {

@Override

public void run() {

while (true) {

progress += 0.02f;

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

mHandler.sendEmptyMessage(PROGRESS_MESSAGE);//每隔100毫秒发送一次消息,对进度球进度进行更新。

}

}

}).start();

}

}

上面代码在inAction()中开一个线程,每隔100毫秒发送消息,在handler中处理更新,在handler使用中并没有直接重写hanldeMessage方法,而是传入Handler.Callback并在callback中实现handleMessage方法,这样可以防止内存泄漏。实际应用中,可以是跟业务相关的具体进度。

总结

自定义进度球,用的是继承view,并且通过自定义画笔,重写onDraw()方法来实现,一般自定义view都会重写onDraw()方法,一般进度条都是ClipDrawable来实现的。

源码地址:进度球代码

带波浪的进度球

上面已经实现了简单的进度球,但是效果不是很好,根据评论区中的提议加上动画和贝塞尔曲线波纹实现了下面的效果,只取了进度处于某一固定进度的动画效果如图:

准备知识

二阶贝塞尔曲线

贝塞尔曲线是用一系列点来控制曲线状态的,将这些点简单分为两类:

二阶贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)函数方程如下:

二阶曲线由两个数据点(P0 和 P2),一个控制点(P1)来描述曲线状态,大致如下:

android中自带实现二阶贝塞尔曲线的api,在Path类中的函数quadTo 。

public void quadTo (float x1,

float y1,

float x2,

float y2)

其中(x1,y1)是上图中控制点p1的坐标,(x2,y2)是上图中数据点结束位置p2的坐标,数据点p0的默认坐标是(0,0),也可以用函数moveTo(x,y)来改变p0坐标。要实现上面进度球进度的波动效果,就要将两个贝塞尔曲线结合起来,并且动态的改变两个贝塞尔曲线的数据点和控制点,这样就会使用户感觉到波动的效果。

实现

/**

* Created time 17:24.

*

* @author huhanjun

* @since 2019/1/2

*/

public class BezierFloatView extends View {

private double rArc=0;

private double percent=0;

public BezierFloatView(Context context) {

super(context);

}

public BezierFloatView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

initPaint();

initAnimator();

}

private RectF rectF;

private int mWidth, mHeight;//画布的宽带和高度

private float cycleWidth, cycleHeight = 30f;//周期的宽度和高度

private Path pathRipple;//画的路径

private Paint paintRipple;//画笔

private float moveSet = 0;//移动的值

private ValueAnimator animator;//动画

private boolean isStart = false;

/**

* 初始化动画

*/

private void initAnimator() {

animator = ValueAnimator.ofFloat(0, mWidth);

animator.setRepeatCount(ValueAnimator.INFINITE);

animator.setDuration(800);

animator.setInterpolator(new LinearInterpolator());

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator valueAnimator) {

percent=valueAnimator.getAnimatedFraction();

moveSet = valueAnimator.getAnimatedFraction() * mWidth;

invalidate();

}

});

}

/**

* 初始化画的路径

*/

private void initPath() {

rArc = mWidth*(1-2*percent);

double angle= Math.acos(rArc/mWidth);

pathRipple = new Path();

pathRipple.moveTo(-6 * cycleWidth + moveSet, 0);

pathRipple.quadTo(-5 * cycleWidth + moveSet, cycleHeight, -4 * cycleWidth + moveSet, 0);

pathRipple.quadTo(-3 * cycleWidth + moveSet, -cycleHeight, -2 * cycleWidth + moveSet, 0);

pathRipple.quadTo(-cycleWidth + moveSet, cycleHeight, moveSet, 0);

pathRipple.quadTo(cycleWidth + moveSet, -cycleHeight, 2 * cycleWidth + moveSet, 0);

pathRipple.addArc(rectF,0,180);

pathRipple.close();

pathRipple.setFillType(Path.FillType.WINDING);

}

/**

* 初始化画笔

*/

private void initPaint() {

paintRipple = new Paint();

paintRipple.setStrokeWidth(2);

paintRipple.setStyle(Paint.Style.FILL);

paintRipple.setColor(Color.BLUE);

paintRipple.setAntiAlias(true);

}

/**

* 画波纹

*

* @param canvas

*/

private void drawRipple(Canvas canvas) {

initPath();

canvas.drawPath(pathRipple, paintRipple);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

mHeight = h;

mWidth = w;

cycleWidth = mWidth / 4;

float r = Math.min(mWidth,mHeight)*0.48f;

rectF = new RectF(-r,-r,r,r);

initAnimator();

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.translate(mWidth / 2, mHeight / 2);

drawRipple(canvas);

}

/**

* 开始动画

*/

public void start() {

if (isStart) return;

isStart = true;

if (animator == null) {

initAnimator();

}

animator.start();

}

/**

* 结束动画

*/

public void stop() {

if (!isStart) return;

isStart = false;

moveSet = 0;

animator.cancel();

animator = null;

invalidate();

}

}

在initPath()中绘制了两条贝塞尔曲线,通过动态的改变moveset的值来改变p0,p2的值,形成波动效果,通过pathRipple.addArc(rectF,0,180);实现一个与贝塞尔曲线形成包围的半圆,通过start()来开始动画,通过stop()来结束动画。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

球体动画Android,Android自定义View实现简单炫酷的球体进度球实例代码相关推荐

  1. Android自定义View之实现简单炫酷的球体进度球

    前言 最近一直在研究自定义view,正好项目中有一个根据下载进度来实现球体进度的需求,所以自己写了个进度球,代码非常简单.先看下效果: 效果还是非常不错的. 准备知识 要实现上面的效果我们只要掌握两个 ...

  2. android canvas_Android 自定义View篇(七)实现环形进度条效果

    前言 Android 自定义 View 是高级进阶不可或缺的内容,日常工作中,经常会遇到产品.UI 设计出花里胡哨的界面.当系统自带的控件不能满足开发需求时,就只能自己动手撸一个效果. 本文就带自定义 ...

  3. Android利用自定义View实现简单的足球战术板

    参考自:http://blog.csdn.net/lmj623565791/article/details/46858663 学习Android初期,之前接触了一些UI设计,突发奇想想要做一个简单的足 ...

  4. android 自定义特效,Android自定义View:实现炫酷的点赞特效

    闲暇时间,看到直播软件都有点赞的爆炸效果,所以也就试着写了一个点赞效果,写的不好亲们勿怪! 这里只是简单说明,具体可查看源码:可查看源码 演示如下: 分析: 1.开始加载一个心形View 2.点击心形 ...

  5. android自定义水波纹,Android自定义View——实现水波纹效果类似剩余流量球(示例代码)...

    最近突然手痒就想搞个贝塞尔曲线做个水波纹效果玩玩,终于功夫不负有心人最后实现了想要的效果,一起来看下吧: 效果图镇楼 一:先一步一步来分解一下实现的过程 需要绘制一个正弦曲线(sin)或者余弦曲线(c ...

  6. 自定义View实现Canvas炫酷效果

    效果: 整个效果分为旋转.扩散聚合.水波纹效果,首先在定义好一些变量后,要先定义一个抽象类SplashState,提供抽象方法drawState供子类实现. /*** 这个抽象类,对外提供drawSt ...

  7. android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球

    Android自定义View--实现水波纹效果类似剩余流量球 三个点   pre   ber   block   span   初始化   move   理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...

  8. Android 系统(264)---android进阶——自定义View

    android进阶--自定义View 软件架构 01.自定义View简介 - onMeasure,onDraw,自定义属性  https://www.jianshu.com/p/48944aad200 ...

  9. 【Android】自定义View、画家(画布)Canvas与画笔Paint的应用——画图、涂鸦板app的实现

    利用一个简单的画图app来说明安卓的图形处理类与自定义View的应用. 如下图,有一个供用户自己任意画图.涂鸦的app, 这里不做那么花俏了,仅提供黑白两色,但可以改变笔尖的粗细. 实质上这里的橡皮擦 ...

最新文章

  1. codeforces_A. Salem and Sticks_数组/暴力
  2. Spring 事务配置5种方式
  3. derby数据库操作比较难理解的错误及解决方法大全
  4. markdown文件便捷说明
  5. Google大牛涉嫌性骚扰被停职,NIPS官方致歉,传闻多时的AI圈黑幕终于被撕开
  6. php数据库添加会员等级显示,给ECSHOP后台订单列表加上显示会员等级
  7. mobomarket android,MoboMarket
  8. 面试官:你背了几道面试题就敢说熟悉Java源码?对不起,我们不招连源码都不会看的人
  9. 筛选法建立初始堆_MTT法检测细胞增殖
  10. matlab构造arma模型,ARMA模型构建及MATLAB实现
  11. Python 玩转数据 3 - NumPy ndarray Array Indexing, Slicing, Striding, View Subarray,Copy Subarray
  12. TapTap 发布开发者服务:降低开发者研运成本 聚焦创作优质内容
  13. 剑指offer之数组中重复的数(Java实现)
  14. Java实例项目之英尺转换
  15. echarts 3D地图点击事件
  16. Nginx 414 Request-URI Too Large报错解决方法
  17. 关键词指数是什么意思?
  18. HYKSVCAO2V4F3电液伺服阀控制器
  19. 3DMAX渲染高分辨率图像教程
  20. 【ArcGIS】1. License Server Administrator点击启动没反应

热门文章

  1. 软链接,xcode接lua文件夹
  2. asp.net MVC 验证错误信息本地化
  3. 将win7笔记本电脑变身WiFi热点,让手机、ipad共享上网!
  4. ipvs学习笔记(二)
  5. XXX管理平台系统——项目风险
  6. SQL2000触发器
  7. Spring Data JPA简单学习
  8. P10全彩屏C语言编程,STC90C52RC驱动P10LED屏的程序
  9. vs studio2015导入本地项目_Visual Studio2019自定义项目模板
  10. 【git系列】简单入门git命令一