Android-两个小球不停的绕中心旋转的进度条
2015-08-08 23:11
555 查看
转载请标明出处:
/article/1825742.html
本文出自:海龙的博客
一、概述
最近做了一个比较清新的进度条,没啥难度的,就是涉及到属性动画和canvas绘制圆形的知识,因为群里有一个问怎么实现的,这里就稍微写了一下原理,先看效果图
二、效果图
Gif录制的帧数有点低,导致稍微有点卡,但是在真实运行的时候一点都不卡
三、实现原理
自定义view
自定义属性动画
canvas画圆
四、代码实现
因为代码非常简单,注释也非常详细,看一下代码就明白了,这里就直接贴代码了:
这里需要注意一个地方,因为我们用到了属性动画,在这里:
其中radius是我们定义的Ball对象的半径属性,这个在混淆的时候会有问题,我们在这里把有关radius都@Keep掉,不让proguard混淆
但是目前Gradle没有启动这个插件,所以需要我们手动开启@Keep
五、开始@Keep防止混淆注解
在app/proguard-rules.pro里面添加
这样就实现了一个清新的两球绕中心滚动的进度条了!
最后附上源码下载地址:github-TwoBallRotationProgressBar
/article/1825742.html
本文出自:海龙的博客
一、概述
最近做了一个比较清新的进度条,没啥难度的,就是涉及到属性动画和canvas绘制圆形的知识,因为群里有一个问怎么实现的,这里就稍微写了一下原理,先看效果图
二、效果图
Gif录制的帧数有点低,导致稍微有点卡,但是在真实运行的时候一点都不卡
三、实现原理
自定义view
自定义属性动画
canvas画圆
四、代码实现
因为代码非常简单,注释也非常详细,看一下代码就明白了,这里就直接贴代码了:
package com.hhl.twoballrotationprogress; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.ColorInt; import android.support.annotation.Keep; import android.util.AttributeSet; import android.view.View; import android.view.animation.DecelerateInterpolator; /** * 两个颜色的小球循环旋转, * 目前只支持代码设置颜色、最大半径、最小半径等属性 * version 1.0 * //TODO 2.0 添加xml自定义属性支持 * Created by HanHailong on 15/8/07. */ public class TwoBallRotationProgressBar extends View { //默认小球最大半径 private final static int DEFAULT_MAX_RADIUS = 15; //默认小球最小半径 private final static int DEFAULT_MIN_RADIUS = 5; //默认两个小球运行轨迹直径距离 private final static int DEFAULT_DISTANCE = 20; //默认第一个小球颜色 private final static int DEFAULT_ONE_BALL_COLOR = Color.parseColor("#40df73"); //默认第二个小球颜色 private final static int DEFAULT_TWO_BALL_COLOR = Color.parseColor("#ffdf3e"); //默认动画执行时间 private final static int DEFAULT_ANIMATOR_DURATION = 1000; //画笔 private Paint mPaint; //球的最大半径 private float maxRadius = DEFAULT_MAX_RADIUS; //球的最小半径 private float minRadius = DEFAULT_MIN_RADIUS; //两球旋转的范围距离 private int distance = DEFAULT_DISTANCE; //动画的时间 private long duration = DEFAULT_ANIMATOR_DURATION; private Ball mOneBall; private Ball mTwoBall; private float mCenterX; private float mCenterY; private AnimatorSet animatorSet; public TwoBallRotationProgressBar(Context context) { this(context, null); } public TwoBallRotationProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TwoBallRotationProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mOneBall = new Ball(); mTwoBall = new Ball(); mOneBall.setColor(DEFAULT_ONE_BALL_COLOR); mTwoBall.setColor(DEFAULT_TWO_BALL_COLOR); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); configAnimator(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mCenterX = w / 2; mCenterY = h / 2; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mCenterX = getWidth() / 2; mCenterY = getHeight() / 2; } @Override protected void onDraw(Canvas canvas) { //画两个小球,半径小的先画,半径大的后画 if (mOneBall.getRadius() > mTwoBall.getRadius()) { mPaint.setColor(mTwoBall.getColor()); canvas.drawCircle(mTwoBall.getCenterX(), mCenterY, mTwoBall.getRadius(), mPaint); mPaint.setColor(mOneBall.getColor()); canvas.drawCircle(mOneBall.getCenterX(), mCenterY, mOneBall.getRadius(), mPaint); } else { mPaint.setColor(mOneBall.getColor()); canvas.drawCircle(mOneBall.getCenterX(), mCenterY, mOneBall.getRadius(), mPaint); mPaint.setColor(mTwoBall.getColor()); canvas.drawCircle(mTwoBall.getCenterX(), mCenterY, mTwoBall.getRadius(), mPaint); } } /** * 配置属性动画 */ private void configAnimator() { //中间半径大小 float centerRadius = (maxRadius + minRadius) * 0.5f; //第一个小球缩放动画,通过改变小球的半径 //半径变化规律:中间大小->最大->中间大小->最小->中间大小 ObjectAnimator oneScaleAnimator = ObjectAnimator.ofFloat(mOneBall, "radius", centerRadius, maxRadius, centerRadius, minRadius, centerRadius); //无限循环 oneScaleAnimator.setRepeatCount(ValueAnimator.INFINITE); //第一个小球位移动画,通过改变小球的圆心 ValueAnimator oneCenterAnimator = ValueAnimator.ofFloat(-1, 0, 1, 0, -1); oneCenterAnimator.setRepeatCount(ValueAnimator.INFINITE); oneCenterAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (Float) animation.getAnimatedValue(); float x = mCenterX + (distance) * value; mOneBall.setCenterX(x); //不停的刷新view,让view不停的重绘 invalidate(); } }); //第二个小球缩放动画 //变化规律:中间大小->最小->中间大小->最大->中间大小 ObjectAnimator twoScaleAnimator = ObjectAnimator.ofFloat(mTwoBall, "radius", centerRadius, minRadius, centerRadius, maxRadius, centerRadius); twoScaleAnimator.setRepeatCount(ValueAnimator.INFINITE); //第二个小球位移动画 ValueAnimator twoCenterAnimator = ValueAnimator.ofFloat(1, 0, -1, 0, 1); twoCenterAnimator.setRepeatCount(ValueAnimator.INFINITE); twoCenterAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (Float) animation.getAnimatedValue(); float x = mCenterX + (distance) * value; mTwoBall.setCenterX(x); } }); //属性动画集合 animatorSet = new AnimatorSet(); //四个属性动画一块执行 animatorSet.playTogether(oneScaleAnimator, oneCenterAnimator, twoScaleAnimator, twoCenterAnimator); //动画一次运行时间 animatorSet.setDuration(DEFAULT_ANIMATOR_DURATION); //时间插值器,这里表示动画开始最快,结尾最慢 animatorSet.setInterpolator(new DecelerateInterpolator()); } /** * 小球 */ public class Ball { @Keep private float radius;//半径 private float centerX;//圆心 private int color;//颜色 @Keep public float getRadius() { return radius; } @Keep public void setRadius(float radius) { this.radius = radius; } public float getCenterX() { return centerX; } public void setCenterX(float centerX) { this.centerX = centerX; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } } @Override public void setVisibility(int v) { if (getVisibility() != v) { super.setVisibility(v); if (v == GONE || v == INVISIBLE) { stopAnimator(); } else { startAnimator(); } } } @Override protected void onVisibilityChanged(View changedView, int v) { super.onVisibilityChanged(changedView, v); if (v == GONE || v == INVISIBLE) { stopAnimator(); } else { startAnimator(); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); startAnimator(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); stopAnimator(); } /** * 设置第一个球的颜色 * * @param color */ public void setOneBallColor(@ColorInt int color) { mOneBall.setColor(color); } /** * 设置第二个球的颜色 * * @param color */ public void setmTwoBallColor(@ColorInt int color) { mTwoBall.setColor(color); } /** * 设置球的最大半径 * * @param maxRadius */ public void setMaxRadius(float maxRadius) { this.maxRadius = maxRadius; configAnimator(); } /** * 设置球的最小半径 * * @param minRadius */ public void setMinRadius(float minRadius) { this.minRadius = minRadius; configAnimator(); } /** * 设置两个球旋转的最大范围距离 * * @param distance */ public void setDistance(int distance) { this.distance = distance; } public void setDuration(long duration) { this.duration = duration; if (animatorSet != null) { animatorSet.setDuration(duration); } } /** * 开始动画 */ public void startAnimator() { if (getVisibility() != VISIBLE) return; if (animatorSet.isRunning()) return; if (animatorSet != null) { animatorSet.start(); } } /** * 结束停止动画 */ public void stopAnimator() { if (animatorSet != null) { animatorSet.end(); } } }
这里需要注意一个地方,因为我们用到了属性动画,在这里:
//第一个小球缩放动画,通过改变小球的半径 //半径变化规律:中间大小->最大->中间大小->最小->中间大小 ObjectAnimator oneScaleAnimator = ObjectAnimator.ofFloat(mOneBall, "radius", centerRadius, maxRadius, centerRadius, minRadius, centerRadius);
其中radius是我们定义的Ball对象的半径属性,这个在混淆的时候会有问题,我们在这里把有关radius都@Keep掉,不让proguard混淆
/** * 小球 */ public class Ball { //防止混淆 @Keep private float radius;//半径 private float centerX;//圆心 private int color;//颜色 //防止混淆 @Keep public float getRadius() { return radius; } //防止混淆 @Keep public void setRadius(float radius) { this.radius = radius; } public float getCenterX() { return centerX; } public void setCenterX(float centerX) { this.centerX = centerX; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } }
但是目前Gradle没有启动这个插件,所以需要我们手动开启@Keep
五、开始@Keep防止混淆注解
在app/proguard-rules.pro里面添加
#手动启用support keep注解 #http://tools.android.com/tech-docs/support-annotations -keep,allowobfuscation @interface android.support.annotation.Keep -keep @android.support.annotation.Keep class * -keepclassmembers class * { @android.support.annotation.Keep *; }
这样就实现了一个清新的两球绕中心滚动的进度条了!
最后附上源码下载地址:github-TwoBallRotationProgressBar
相关文章推荐
- Android 中odex转成dex
- android library引用失败的解决办法
- Android Studio快捷键
- Android SDK Manager 更新代理配置
- Android Support兼容包详解
- Android中的Parcelable接口
- Android应用程序构成
- Android studio使用笔记。。。
- Android 获取子组件
- Android--编程方法之外的常识
- Android中的ViewPager和 PagerAdapter的初步理解和使用
- Android View(一)
- AndroidAnnotations使用
- 设置一个简单的安卓启动页面
- 【Android先进】我们为什么要创建Activity基类Activity什么是一般的基类方法
- android学习笔记(5)Activity生命周期学习
- android studio
- 【Android资料】Android软键盘显示模式总结
- 【干货】Android studio教程与问题汇总
- AndroidStudio中修改包名