标签:
之前帮别人写了一个不是那么优美的圆形进度条,效果图大家也看过了。但是后某人不满意,说原应用是倒计时时间最后5s,才开始显示数字的,同时转完一圈需要的时间只能是30s左右。然后我掐时间看了一下虽然总时间设置的是30s,但是总共转完一圈却耗费了50多秒的样子。
问题出来了:
1. 转圈总时间30s不正确
2. 数字显示时间不正确
3. 数字1的动画没原应用的好(2144手机令牌)
花了一个小时搞了一下,忍不住终于射出来了什么东西,解决了上面的3个问题(请看1从有到无);国际惯例效果图先行,先看下改善之后的效果图(不好请不要吐我口水)
当对于一个问题无从下手的话,有时候反编译看下别人家的源代码也是不错的选择。反编译工具用的是Android逆向助手。
看了下它的代码,发现他原来是用定时器区去完成这个工作的
public class MyProgressCount extends CountDownTimer
{
public MyProgressCount()
{
super(30000L, 25L);
}
public void onFinish()
{
start();
}
public void onTick(long paramLong)
{
MainFragment.this.count = (MainFragment.this.max - (float)paramLong);
MainFragment.this.progress_bar.setProgress(MainFragment.this.count);
MainFragment.this.circleRadius = (MainFragment.this.progressBar_width / 2);
MainFragment.this.circleX = (MainFragment.this.window_width / 2 - MainFragment.this.circleRadius);
MainFragment.this.circleY = (MainFragment.this.circleY_init + MainFragment.this.circleRadius);
if (MainFragment.this.count >= MainFragment.this.max - 200.0F)
{
MainFragment.this.round_text.setVisibility(8);
MainFragment.this.password_time = (DateUtils.getStringToDate(DateUtils.getCurrentDate()) + MainFragment.this.d_value);
MainFragment.this.count = 0.0F;
MainFragment.this.password = Util.DynamicPassword(MainFragment.this.uid, MainFragment.this.password_time - (MainFragment.this.password_time % 30L), MainFragment.this.token);
DbManage.getInstance(MainFragment.this.activity).saveActionStr(MainFragment.this.password, MainFragment.this.password_time - (MainFragment.this.password_time % 30L));
MainFragment.this.stringArr = MainFragment.this.password.toCharArray();
MainFragment.this.dynamic_password.setText(MainFragment.this.stringArr[0] + " " + MainFragment.this.stringArr[1] + " " + MainFragment.this.stringArr[2] + " " + MainFragment.this.stringArr[3] + " " + MainFragment.this.stringArr[4] + " " + MainFragment.this.stringArr[5]);
}
if (MainFragment.this.count > MainFragment.this.max * 5.0F / 6.0F)
{
float f = MainFragment.this.max * 5.0F / 6.0F;
f = (float)(MainFragment.this.count / 1000.0D);
double d = 3.141592653589793D * 12.0F * f / 180.0D;
int i = (int)(Math.sin(d) * MainFragment.this.progress_bar.getWidth() / 2.0D);
int j = (int)(Math.cos(d) * MainFragment.this.progress_bar.getWidth() / 2.0D);
Util.setLayout(MainFragment.this.round_text, MainFragment.this.circleX + MainFragment.this.circleRadius - Math.abs(i), MainFragment.this.circleY - Math.abs(j));
i = ((Integer)ColorUtils.evaluate((float)((MainFragment.this.count / MainFragment.this.max - 0.75D) * 4.0D), Integer.valueOf(-1853686), Integer.valueOf(-3407872))).intValue();
MainFragment.this.round_text.setBackgroundDrawable(Util.getRoundBg(i, 100));
MainFragment.this.round_text.setTextColor(-1);
if ((f >= 25.0F) && (f <= 30.0F))
{
MainFragment.this.round_text.setVisibility(0);
MainFragment.this.round_text.setText((int)(31.0F - f));
if ((f >= 29.0F) && (f < 30.0F) && (!(MainFragment.this.scaleAnimation.hasStarted())))
{
MainFragment.this.round_text.setAnimation(MainFragment.this.scaleAnimation);
MainFragment.this.scaleAnimation.setAnimationListener(new Animation.AnimationListener()
{
public void onAnimationEnd(Animation paramAnimation)
{
MainFragment.this.scaleAnimation = new ScaleAnimation(1.0F, 0.0F, 1.0F, 0.0F, 1, 0.5F, 1, 0.5F);
MainFragment.this.scaleAnimation.setDuration(MainFragment.this.duration);
}
public void onAnimationRepeat(Animation paramAnimation)
{
}
public void onAnimationStart(Animation paramAnimation)
{
}
});
MainFragment.this.scaleAnimation.start();
}
}
while (true)
{
MainFragment.this.round_text.invalidate();
return;
MainFragment.this.round_text.setVisibility(8);
}
}
MainFragment.this.round_text.setVisibility(8);
}
}
至于里面数字的显示用的是一个TextView
动态改变他的位置以及内容和背景颜色,然后配合上CircleProgressBar
就行了(当然里面涉及到有颜色值改变的计算),详情看下文给出的源代码。
当然看了反编译代码思路说起来很轻松,估计是个稍微会一点安卓的人都知道,那下面我们改进入正题了(talk is cheap,show me the fucking code).
里面牵涉到4个类,工具类:Util
和ColorUtils
;界面类:TestActivity01
和CircleProgressBar
。
先看下CircleProgressBar
里面有些什么狗屎东西:
package com.example.tangxb.myapplication;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
public class CircleProgressBar extends View {
private static final int DEFAULT_BACKGROUND_COLOR = Color.parseColor("#ffffff");
private static final int DEFAULT_MAX = 100;
private static final int DEFAULT_PROGRESS_COLOR = Color.parseColor("#54bfad");
private static final int DEFAULT_PROGRESS_END_COLOR = 0;
private static final int DEFAULT_SIZE = 80;
private static final boolean DEFAULT_TRANSITION_ENABLE = false;
private static final int END_ANGLE = 360;
private static final float MAX_SWEEP_ANGLE = 360.0F;
private static final String TAG = "ArcProgressBar";
private float DEFAULT_STROKE_WIDTH;
int c;
Context context;
SizeChangeListener l;
private float mMax;
private Path mPath;
private float mProgress;
private int mProgressBackgroundColor;
private Paint mProgressBgPaint;
private RectF mProgressBgRectF;
private int mProgressColor;
private int mProgressEndColor;
private int mProgressEndColor2;
private Paint mProgressPaint;
private Paint mProgressPaintEnd;
private RectF mProgressRectF;
private float mStrokeWith;
private float unitAngle;
public CircleProgressBar(Context paramContext) {
this(paramContext, null);
}
public CircleProgressBar(Context paramContext, AttributeSet paramAttributeSet) {
this(paramContext, paramAttributeSet, 0);
}
public CircleProgressBar(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
super(paramContext, paramAttributeSet, paramInt);
this.DEFAULT_STROKE_WIDTH = 6.0F;
this.mProgressRectF = new RectF(0.0F, 0.0F, 0.0F, 0.0F);
this.mProgressBgRectF = new RectF(0.0F, 0.0F, 0.0F, 0.0F);
this.mStrokeWith = 0.0F;
this.unitAngle = 0.0F;
this.context = paramContext;
loadStyledAttr(paramContext, paramAttributeSet, paramInt);
initPaint();
}
private void drawProgress(Canvas paramCanvas) {
int i = getWidth() / 2;
int j = i - Util.dip2px(this.context, 13.0F);
paramCanvas.drawArc(new RectF(i - j, i - j, i + j, i + j), getStartAngle(), getSweepAngel(), getUseCenter(), this.mProgressPaint);
}
private void drawProgressBg(Canvas paramCanvas) {
int i = getWidth() / 2;
int j = i - Util.dip2px(this.context, 20.0F);
paramCanvas.drawArc(new RectF(i - j, i - j, i + j, i + j), getStartAngle(), 360.0F, true, this.mProgressBgPaint);
}
private void drawProgressNum(Canvas paramCanvas) {
this.mProgressBgRectF.left = 30.0F;
this.mProgressBgRectF.top = 30.0F;
this.mProgressBgRectF.right = 105.0F;
this.mProgressBgRectF.bottom = 105.0F;
Paint localPaint = new Paint(1);
localPaint.setColor(Color.rgb(216, 76, 75));
localPaint.setStyle(Paint.Style.STROKE);
paramCanvas.drawArc(this.mProgressBgRectF, getStartAngle(), 360.0F, getUseCenter(), localPaint);
}
private int getStartAngle() {
return -90;
}
private float getSweepAngel() {
return (this.unitAngle * this.mProgress);
}
private boolean getUseCenter() {
return false;
}
private void initPaint() {
this.mPath = new Path();
this.mProgressPaint = new Paint(1);
this.mProgressPaint.setColor(this.mProgressColor);
this.mProgressBgPaint = new Paint(1);
this.mProgressBgPaint.setColor(this.mProgressBackgroundColor);
this.mProgressBgPaint.setAntiAlias(true);
this.mProgressPaint.setStyle(Paint.Style.STROKE);
this.mProgressPaint.setStrokeJoin(Paint.Join.ROUND);
this.mProgressPaint.setStrokeWidth(Util.dip2px(this.context, 10.0F));
this.mProgressBgPaint.setStyle(Paint.Style.FILL);
this.mProgressBgPaint.setStrokeWidth(this.mStrokeWith);
}
private void loadStyledAttr(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
// 颜色设置
this.mProgressBackgroundColor = DEFAULT_BACKGROUND_COLOR;
this.mProgressColor = Color.parseColor("#ff48d502");
this.mProgressEndColor = Color.parseColor("#ffe3b70a");
this.mProgressEndColor2 = Color.parseColor("#ffcc0000");
this.mMax = 100;
this.mProgress = 0;
this.DEFAULT_STROKE_WIDTH = Util.dip2px(getContext(), this.DEFAULT_STROKE_WIDTH);
this.mStrokeWith = Util.dip2px(getContext(), this.DEFAULT_STROKE_WIDTH);
}
private int measure(int paramInt) {
int i = View.MeasureSpec.getMode(paramInt);
paramInt = View.MeasureSpec.getSize(paramInt);
if (i == 1073741824)
return paramInt;
return Util.dip2px(getContext(), 80.0F);
}
private void onProgressChanged() {
this.c = ((Integer) ColorUtils.evaluate((float) (this.mProgress / this.mMax * 1.5D), Integer.valueOf(this.mProgressColor), Integer.valueOf(this.mProgressEndColor))).intValue();
this.mProgressPaint.setColor(this.c);
}
private void onProgressChangedEnd() {
this.c = ((Integer) ColorUtils.evaluate((float) ((float) (this.mProgress / this.mMax - 0.75D) * 4.0D), Integer.valueOf(this.mProgressEndColor), Integer.valueOf(this.mProgressEndColor2))).intValue();
this.mProgressPaint.setColor(this.c);
}
private void setUnitProgress() {
this.unitAngle = (360.0F / this.mMax);
}
public float getMax() {
return this.mMax;
}
public double getPrgoress() {
return this.mProgress;
}
protected void onDraw(Canvas paramCanvas) {
drawProgressBg(paramCanvas);
drawProgress(paramCanvas);
}
protected void onMeasure(int paramInt1, int paramInt2) {
setMeasuredDimension(measure(paramInt1), measure(paramInt2));
setUnitProgress();
}
protected void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
this.l.sizeChanged(paramInt1, paramInt2, paramInt3, paramInt4);
super.onSizeChanged(paramInt1, paramInt2, paramInt3, paramInt4);
}
public void setMax(float paramFloat) {
this.mMax = paramFloat;
setUnitProgress();
invalidate();
}
public void setProgress(float paramFloat) {
this.mProgress = paramFloat;
if (paramFloat <= this.mMax * 0.75D)
onProgressChanged();
if (paramFloat > this.mMax * 0.75D)
onProgressChangedEnd();
invalidate();
}
public void setProgressWithAnim(int paramInt1, int paramInt2, long paramLong) {
ValueAnimator localValueAnimator = ValueAnimator.ofInt(new int[]{paramInt1, paramInt2});
localValueAnimator.setDuration(paramLong);
localValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator paramValueAnimator) {
}
});
localValueAnimator.setInterpolator(new LinearInterpolator());
localValueAnimator.start();
}
public void setProgressWithAnim(int paramInt, long paramLong) {
setProgressWithAnim(0, paramInt, paramLong);
}
/**
* 这里可用getViewTreeObserver()去做监听,消除耦合
*
* @param paramSizeChangeListener
*/
public void setSizeChangeListener(SizeChangeListener paramSizeChangeListener) {
this.l = paramSizeChangeListener;
}
public interface SizeChangeListener {
void sizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4);
}
}
源码有点长,但是里面画的东西却很少
protected void onDraw(Canvas paramCanvas) {
drawProgressBg(paramCanvas);
drawProgress(paramCanvas);
}
然后看下TestActivity01
:
package com.example.tangxb.myapplication;
import android.graphics.Color;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.TextView;
/**
* Created by Tangxb on 2016/4/19.
*/
public class TestActivity01 extends AppCompatActivity {
private int circleRadius;
private int circleX;
private int circleY;
private int circleY_init;
private int duration = 1200;
private float count = 0.0F;
private float max;
private MyProgressCount progressCount;
private CircleProgressBar progress_bar;
/**
* 宽高为20dp的TextView
*/
private TextView round_text;
// 第一个效果表现没有第二个好
Animation scaleAnimation1 = new ScaleAnimation(1.0F, 0.4F, 1.0F, 0.4F, Animation.RELATIVE_TO_SELF, 0.3F, Animation.RELATIVE_TO_SELF, 0.2F);
// 使用第二个替代了第一个
Animation scaleAnimation = new ScaleAnimation(1.0F, 0.0F, 1.0F, 0.0F, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F);
private int window_width;
private int progressBar_width;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acttivity_test);
init();
}
private void init() {
scaleAnimation.setDuration(this.duration);
max = 30000.0F;
circleY_init = Util.dip2px(this, 85.0F);
window_width = getWindowManager().getDefaultDisplay().getWidth();
progress_bar = ((CircleProgressBar) findViewById(R.id.cpb));
round_text = ((TextView) findViewById(R.id.tv));
progress_bar.setMax(max);
progress_bar.setSizeChangeListener(new CircleProgressBar.SizeChangeListener() {
public void sizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
progressBar_width = progress_bar.getWidth();
if (progressCount == null) {
progressCount = new MyProgressCount();
}
progressCount.start();
}
});
}
@Override
protected void onStart() {
super.onStart();
if (progressBar_width != 0) {
if (progressCount == null) {
progressCount = new MyProgressCount();
}
progressCount.start();
}
}
@Override
protected void onStop() {
super.onStop();
if (progressCount != null) {
progressCount.cancel();
progressCount = null;
}
}
class MyProgressCount extends CountDownTimer {
public MyProgressCount() {
super(30000L, 25L);
}
public void onFinish() {
start();
}
public void onTick(long paramLong) {
count = (max - (float) paramLong);
// 设置进度
progress_bar.setProgress(count);
circleRadius = (progressBar_width / 2);
circleX = (window_width / 2 - circleRadius);
circleY = (circleY_init + circleRadius);
if (count >= max - 200.0F) {
}
if (count > max * 5.0F / 6.0F) {
float f = (float) (count / 1000.0D);
// 计算弧度值(sin需要的是弧度值不是角度值),至于是怎么得到的,数学渣渣表示懵逼
double d = Math.PI * 12.0F * f / 180.0D;
int i = (int) (Math.sin(d) * progress_bar.getWidth() / 2.0D);
int j = (int) (Math.cos(d) * progress_bar.getWidth() / 2.0D);
// 这里请注意里面使用的FrameLayout.LayoutParams,所以容器请用FrameLayout
Util.setLayout(round_text, circleX + circleRadius - Math.abs(i), circleY - Math.abs(j));
i = ((Integer) ColorUtils.evaluate((float) ((count / max - 0.75D) * 4.0D), Integer.valueOf(-1853686), Integer.valueOf(-3407872))).intValue();
round_text.setBackgroundDrawable(Util.getRoundBg(i, 100));
round_text.setTextColor(Color.WHITE);
if ((f >= 25.0F) && (f <= 30.0F)) {
round_text.setVisibility(View.VISIBLE);
round_text.setText((int) (31.0F - f) + "");
if ((f >= 29.0F) && (f < 30.0F) && (!(scaleAnimation.hasStarted()))) {
round_text.setAnimation(scaleAnimation);
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationEnd(Animation paramAnimation) {
scaleAnimation = new ScaleAnimation(1.0F, 0.0F, 1.0F, 0.0F, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F);
scaleAnimation.setDuration(duration);
// 设置数字的text为GONE状态
round_text.setVisibility(View.GONE);
}
public void onAnimationRepeat(Animation paramAnimation) {
}
public void onAnimationStart(Animation paramAnimation) {
// 设置数字的text为VISIBLE状态
round_text.setVisibility(View.VISIBLE);
}
});
scaleAnimation.start();
}
}
}
}
}
}
附上ColorUtils
和Util
以及xml
文件
package com.example.tangxb.myapplication;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/**
* Created by Tangxb on 2016/7/25.
*/
public class Util {
public static int dip2px(Context paramContext, float paramFloat) {
return (int) (paramFloat * paramContext.getResources().getDisplayMetrics().density + 0.5F);
}
public static void setLayout(View paramView, int paramInt1, int paramInt2) {
ViewGroup.MarginLayoutParams localMarginLayoutParams = new ViewGroup.MarginLayoutParams(paramView.getLayoutParams());
localMarginLayoutParams.setMargins(paramInt1 - 14, paramInt2 + 10, localMarginLayoutParams.width + paramInt1, localMarginLayoutParams.height + paramInt2);
paramView.setLayoutParams(new FrameLayout.LayoutParams(localMarginLayoutParams));
}
public static Drawable getRoundBg(int paramInt1, int paramInt2) {
ShapeDrawable localShapeDrawable = new ShapeDrawable(new RoundRectShape(new float[]{paramInt2, paramInt2, paramInt2, paramInt2, paramInt2, paramInt2, paramInt2, paramInt2}, null, null));
paramInt2 = paramInt1;
if (paramInt1 == -1)
paramInt2 = -1;
localShapeDrawable.getPaint().setColor(paramInt2);
return localShapeDrawable;
}
}
package com.example.tangxb.myapplication;
/**
* Created by Tangxb on 2016/7/25.
*/
public class ColorUtils {
public static Object evaluate(float paramFloat, Object paramObject1, Object paramObject2)
{
int l = ((Integer)paramObject1).intValue();
int i = l >> 24 & 0xFF;
int j = l >> 16 & 0xFF;
int k = l >> 8 & 0xFF;
l &= 255;
int i1 = ((Integer)paramObject2).intValue();
return Integer.valueOf((int)(((i1 >> 24 & 0xFF) - i) * paramFloat) + i << 24 | (int)(((i1 >> 16 & 0xFF) - j) * paramFloat) + j << 16 | (int)(((i1 >> 8 & 0xFF) - k) * paramFloat) + k << 8 | (int)(((i1 & 0xFF) - l) * paramFloat) + l);
}
public static Object evaluate2(float paramFloat, Object paramObject1, Object paramObject2, Object paramObject3)
{
int l = ((Integer)paramObject1).intValue();
int i = l >> 24 & 0xFF;
int j = l >> 16 & 0xFF;
int k = l >> 8 & 0xFF;
l &= 255;
int i1 = ((Integer)paramObject2).intValue();
int i2 = ((Integer)paramObject3).intValue();
return Integer.valueOf((int)(((i1 >> 24 & 0xFF) - i - (i2 >> 24 & 0xFF)) * paramFloat) + i << 24 | (int)(((i1 >> 16 & 0xFF) - j - (i2 >> 16 & 0xFF)) * paramFloat) + j << 16 | (int)(((i1 >> 8 & 0xFF) - k - (i2 >> 8 & 0xFF)) * paramFloat) + k << 8 | (int)(((i1 & 0xFF) - l - (i2 & 0xFF)) * paramFloat) + l);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="385.0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300.0dp"
android:layout_marginTop="85.0dp">
<com.example.tangxb.myapplication.CircleProgressBar
android:id="@+id/cpb"
android:layout_width="300.0dp"
android:layout_height="300.0dp"
android:layout_centerHorizontal="true" />
</RelativeLayout>
<TextView
android:id="@+id/tv"
android:layout_width="20.0dp"
android:layout_height="20.0dp"
android:gravity="center"
android:textColor="#ff494949" />
</FrameLayout>
</RelativeLayout>
我把里面能够自己还原的部分还原了,然而这里为了偷懒,就没有再用自定义属性去设置颜色值了。
标签:
原文地址:http://blog.csdn.net/t1623183652/article/details/52022683