├── 1.gif ├── bin ├── classes.dex ├── resources.ap_ ├── ProgressBar.apk ├── res │ └── crunch │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ └── drawable-xhdpi │ │ └── ic_launcher.png ├── classes │ └── ryancheng │ │ └── example │ │ └── progressbar │ │ ├── R.class │ │ ├── R$attr.class │ │ ├── R$color.class │ │ ├── R$style.class │ │ ├── R$layout.class │ │ ├── R$string.class │ │ ├── BuildConfig.class │ │ ├── MainActivity.class │ │ ├── R$drawable.class │ │ ├── R$styleable.class │ │ ├── CircularProgress.class │ │ ├── CircularProgress$1.class │ │ ├── CircularProgress$2.class │ │ ├── CircularProgress$3.class │ │ ├── CircularProgressDrawable.class │ │ ├── CircularProgressDrawable$1.class │ │ ├── CircularProgressDrawable$2.class │ │ └── CircularProgressDrawable$3.class ├── dexedLibs │ └── android-support-v4-f5d303d20a440180447b12719621e45f.jar └── AndroidManifest.xml ├── .settings └── org.eclipse.core.resources.prefs ├── libs └── android-support-v4.jar ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── values │ ├── strings.xml │ ├── attrs.xml │ ├── colors.xml │ └── styles.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── layout │ └── activity_main.xml ├── README.md ├── gen └── ryancheng │ └── example │ └── progressbar │ ├── BuildConfig.java │ └── R.java ├── src └── ryancheng │ └── example │ └── progressbar │ ├── MainActivity.java │ ├── CircularProgressDrawable.java │ └── CircularProgress.java ├── .classpath ├── project.properties ├── proguard-project.txt ├── .project └── AndroidManifest.xml /1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/1.gif -------------------------------------------------------------------------------- /bin/classes.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes.dex -------------------------------------------------------------------------------- /bin/resources.ap_: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/resources.ap_ -------------------------------------------------------------------------------- /bin/ProgressBar.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/ProgressBar.apk -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/libs/android-support-v4.jar -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /bin/res/crunch/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/res/crunch/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /bin/res/crunch/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/res/crunch/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /bin/res/crunch/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/res/crunch/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R.class -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #ProgressBar 2 | =========== 3 | 4 | a nice progressbar style 5 | 6 | ![](https://github.com/cr1944/ProgressBar/raw/master/1.gif "ProgressBar") 7 | -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$attr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$attr.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$color.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$color.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$style.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$style.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$layout.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$layout.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$string.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$string.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/BuildConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/BuildConfig.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/MainActivity.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/MainActivity.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$drawable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$drawable.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/R$styleable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/R$styleable.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgress.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgress.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgress$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgress$1.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgress$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgress$2.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgress$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgress$3.class -------------------------------------------------------------------------------- /bin/dexedLibs/android-support-v4-f5d303d20a440180447b12719621e45f.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/dexedLibs/android-support-v4-f5d303d20a440180447b12719621e45f.jar -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgressDrawable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgressDrawable.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$1.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$2.class -------------------------------------------------------------------------------- /bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigerguixh/ProgressBar/HEAD/bin/classes/ryancheng/example/progressbar/CircularProgressDrawable$3.class -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProgressBar 5 | Hello world! 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /gen/ryancheng/example/progressbar/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package ryancheng.example.progressbar; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFC93437 4 | #FF375BF1 5 | #FFF7D23E 6 | #FF34A350 7 | 8 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/ryancheng/example/progressbar/MainActivity.java: -------------------------------------------------------------------------------- 1 | 2 | package ryancheng.example.progressbar; 3 | 4 | import android.app.Activity; 5 | import android.os.Bundle; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | 9 | public class MainActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_main); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ProgressBar 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /bin/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /gen/ryancheng/example/progressbar/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package ryancheng.example.progressbar; 9 | 10 | public final class R { 11 | public static final class attr { 12 | /**

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". 13 | Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), 14 | in (inches), mm (millimeters). 15 |

This may also be a reference to a resource (in the form 16 | "@[package:]type:name") or 17 | theme attribute (in the form 18 | "?[package:][type:]name") 19 | containing a value of this type. 20 | */ 21 | public static final int borderWidth=0x7f010000; 22 | } 23 | public static final class color { 24 | public static final int blue=0x7f040001; 25 | public static final int green=0x7f040003; 26 | public static final int red=0x7f040000; 27 | public static final int yellow=0x7f040002; 28 | } 29 | public static final class drawable { 30 | public static final int ic_launcher=0x7f020000; 31 | } 32 | public static final class layout { 33 | public static final int activity_main=0x7f030000; 34 | } 35 | public static final class string { 36 | public static final int app_name=0x7f050000; 37 | public static final int hello_world=0x7f050001; 38 | } 39 | public static final class style { 40 | /** 41 | Base application theme, dependent on API level. This theme is replaced 42 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 43 | 44 | 45 | Theme customizations available in newer API levels can go in 46 | res/values-vXX/styles.xml, while customizations related to 47 | backward-compatibility can go here. 48 | 49 | 50 | Base application theme for API 11+. This theme completely replaces 51 | AppBaseTheme from res/values/styles.xml on API 11+ devices. 52 | 53 | API 11 theme customizations can go here. 54 | 55 | Base application theme for API 14+. This theme completely replaces 56 | AppBaseTheme from BOTH res/values/styles.xml and 57 | res/values-v11/styles.xml on API 14+ devices. 58 | 59 | API 14 theme customizations can go here. 60 | */ 61 | public static final int AppBaseTheme=0x7f060000; 62 | /** Application theme. 63 | All customizations that are NOT specific to a particular API-level can go here. 64 | */ 65 | public static final int AppTheme=0x7f060001; 66 | } 67 | public static final class styleable { 68 | /** Attributes that can be used with a CircularProgress. 69 |

Includes the following attributes:

70 | 71 | 72 | 73 | 74 | 75 |
AttributeDescription
{@link #CircularProgress_borderWidth ryancheng.example.progressbar:borderWidth}
76 | @see #CircularProgress_borderWidth 77 | */ 78 | public static final int[] CircularProgress = { 79 | 0x7f010000 80 | }; 81 | /** 82 |

This symbol is the offset where the {@link ryancheng.example.progressbar.R.attr#borderWidth} 83 | attribute's value can be found in the {@link #CircularProgress} array. 84 | 85 | 86 |

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". 87 | Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), 88 | in (inches), mm (millimeters). 89 |

This may also be a reference to a resource (in the form 90 | "@[package:]type:name") or 91 | theme attribute (in the form 92 | "?[package:][type:]name") 93 | containing a value of this type. 94 | @attr name ryancheng.example.progressbar:borderWidth 95 | */ 96 | public static final int CircularProgress_borderWidth = 0; 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /src/ryancheng/example/progressbar/CircularProgressDrawable.java: -------------------------------------------------------------------------------- 1 | package ryancheng.example.progressbar; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.animation.ValueAnimator; 6 | import android.graphics.Canvas; 7 | import android.graphics.ColorFilter; 8 | import android.graphics.Paint; 9 | import android.graphics.PixelFormat; 10 | import android.graphics.Rect; 11 | import android.graphics.RectF; 12 | import android.graphics.drawable.Animatable; 13 | import android.graphics.drawable.Drawable; 14 | import android.util.Property; 15 | import android.view.animation.DecelerateInterpolator; 16 | import android.view.animation.Interpolator; 17 | import android.view.animation.LinearInterpolator; 18 | 19 | public class CircularProgressDrawable extends Drawable implements Animatable { 20 | 21 | /** 22 | * 绘制圆弧起始位置角度的动画,这样该圆弧是打圈转的动画 23 | */ 24 | private static final Interpolator ANGLE_INTERPOLATOR = new LinearInterpolator(); 25 | /** 26 | * 绘制圆弧臂长的动画,该动画受 mModeAppearing 控制, 27 | * 当 mModeAppearing 为 false 的时候,圆弧的起始点在增加,圆弧的终止点不变,弧长在逐渐减少; 28 | * 当 mModeAppearing 为 true 的时候, 圆弧的起始点不变,圆弧的终止点变大,弧长在逐渐增加 29 | */ 30 | private static final Interpolator SWEEP_INTERPOLATOR = new DecelerateInterpolator(); 31 | /** 32 | * 圆弧起始位置动画的间隔,也就是多少毫秒圆弧转一圈,可以把该值扩大10倍来查看动画的慢动作 33 | */ 34 | private static final int ANGLE_ANIMATOR_DURATION = 2000; 35 | /** 36 | * 圆弧臂长的动画间隔,也就是臂长从最小到最大值的变化时间,也可以把该值扩大10倍来查看动画的慢动作 37 | */ 38 | private static final int SWEEP_ANIMATOR_DURATION = 600; 39 | /** 40 | * 圆弧的最下臂长是多少度 41 | */ 42 | private static final int MIN_SWEEP_ANGLE = 30; 43 | private final RectF fBounds = new RectF(); 44 | 45 | /** 46 | * 起始位置的动画对象 47 | */ 48 | private ObjectAnimator mObjectAnimatorSweep; 49 | /** 50 | * 臂长的动画对象 51 | */ 52 | private ObjectAnimator mObjectAnimatorAngle; 53 | /** 54 | * 控制臂长是逐渐增加还是逐渐减少 55 | */ 56 | private boolean mModeAppearing; 57 | private Paint mPaint; 58 | /** 59 | * 每次臂长增加 、减少 转换的时候, 圆弧起始位置的偏移量会增加 2 倍的最小臂长 60 | */ 61 | private float mCurrentGlobalAngleOffset; 62 | private float mCurrentGlobalAngle; 63 | private float mCurrentSweepAngle; 64 | private float mBorderWidth; 65 | private boolean mRunning; 66 | 67 | public CircularProgressDrawable(int color, float borderWidth) { 68 | mBorderWidth = borderWidth; 69 | 70 | mPaint = new Paint(); 71 | mPaint.setAntiAlias(true); 72 | mPaint.setStyle(Paint.Style.STROKE); 73 | mPaint.setStrokeWidth(borderWidth); 74 | mPaint.setColor(color); 75 | 76 | setupAnimations(); 77 | } 78 | 79 | @Override 80 | public void draw(Canvas canvas) { 81 | float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset; 82 | float sweepAngle = mCurrentSweepAngle; 83 | if (mModeAppearing) { 84 | sweepAngle += MIN_SWEEP_ANGLE; 85 | } else { 86 | startAngle = startAngle + sweepAngle; 87 | sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE; 88 | } 89 | canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint); 90 | } 91 | 92 | @Override 93 | public void setAlpha(int alpha) { 94 | mPaint.setAlpha(alpha); 95 | } 96 | 97 | @Override 98 | public void setColorFilter(ColorFilter cf) { 99 | mPaint.setColorFilter(cf); 100 | } 101 | 102 | @Override 103 | public int getOpacity() { 104 | return PixelFormat.TRANSPARENT; 105 | } 106 | 107 | private void toggleAppearingMode() { 108 | mModeAppearing = !mModeAppearing; 109 | if (mModeAppearing) { 110 | mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360; 111 | } 112 | } 113 | 114 | @Override 115 | protected void onBoundsChange(Rect bounds) { 116 | super.onBoundsChange(bounds); 117 | fBounds.left = bounds.left + mBorderWidth / 2f + .5f; 118 | fBounds.right = bounds.right - mBorderWidth / 2f - .5f; 119 | fBounds.top = bounds.top + mBorderWidth / 2f + .5f; 120 | fBounds.bottom = bounds.bottom - mBorderWidth / 2f - .5f; 121 | } 122 | 123 | // //////////////////////////////////////////////////////////////////////////// 124 | // ////////////// Animation 125 | 126 | private Property mAngleProperty = new Property(Float.class, "angle") { 127 | @Override 128 | public Float get(CircularProgressDrawable object) { 129 | return object.getCurrentGlobalAngle(); 130 | } 131 | 132 | @Override 133 | public void set(CircularProgressDrawable object, Float value) { 134 | object.setCurrentGlobalAngle(value); 135 | } 136 | }; 137 | 138 | private Property mSweepProperty = new Property(Float.class, "arc") { 139 | @Override 140 | public Float get(CircularProgressDrawable object) { 141 | return object.getCurrentSweepAngle(); 142 | } 143 | 144 | @Override 145 | public void set(CircularProgressDrawable object, Float value) { 146 | object.setCurrentSweepAngle(value); 147 | } 148 | }; 149 | 150 | private void setupAnimations() { 151 | mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f); 152 | mObjectAnimatorAngle.setInterpolator(ANGLE_INTERPOLATOR); 153 | mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION); 154 | mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART); 155 | mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE); 156 | 157 | mObjectAnimatorSweep = ObjectAnimator.ofFloat(this, mSweepProperty, 360f - MIN_SWEEP_ANGLE * 2); 158 | mObjectAnimatorSweep.setInterpolator(SWEEP_INTERPOLATOR); 159 | mObjectAnimatorSweep.setDuration(SWEEP_ANIMATOR_DURATION); 160 | mObjectAnimatorSweep.setRepeatMode(ValueAnimator.RESTART); 161 | mObjectAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE); 162 | mObjectAnimatorSweep.addListener(new Animator.AnimatorListener() { 163 | @Override 164 | public void onAnimationStart(Animator animation) { 165 | 166 | } 167 | 168 | @Override 169 | public void onAnimationEnd(Animator animation) { 170 | 171 | } 172 | 173 | @Override 174 | public void onAnimationCancel(Animator animation) { 175 | 176 | } 177 | 178 | @Override 179 | public void onAnimationRepeat(Animator animation) { 180 | toggleAppearingMode(); 181 | } 182 | }); 183 | } 184 | 185 | @Override 186 | public void start() { 187 | if (isRunning()) { 188 | return; 189 | } 190 | mRunning = true; 191 | // 为了方便测试,可以注释掉下面两个动画中的一个,来 192 | //分别查看每个独立的动画是如何运动的 193 | mObjectAnimatorAngle.start(); 194 | mObjectAnimatorSweep.start(); 195 | invalidateSelf(); 196 | } 197 | 198 | @Override 199 | public void stop() { 200 | if (!isRunning()) { 201 | return; 202 | } 203 | mRunning = false; 204 | mObjectAnimatorAngle.cancel(); 205 | mObjectAnimatorSweep.cancel(); 206 | invalidateSelf(); 207 | } 208 | 209 | @Override 210 | public boolean isRunning() { 211 | return mRunning; 212 | } 213 | 214 | public void setCurrentGlobalAngle(float currentGlobalAngle) { 215 | mCurrentGlobalAngle = currentGlobalAngle; 216 | invalidateSelf(); 217 | } 218 | 219 | public float getCurrentGlobalAngle() { 220 | return mCurrentGlobalAngle; 221 | } 222 | 223 | public void setCurrentSweepAngle(float currentSweepAngle) { 224 | mCurrentSweepAngle = currentSweepAngle; 225 | invalidateSelf(); 226 | } 227 | 228 | public float getCurrentSweepAngle() { 229 | return mCurrentSweepAngle; 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/ryancheng/example/progressbar/CircularProgress.java: -------------------------------------------------------------------------------- 1 | package ryancheng.example.progressbar; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.animation.ValueAnimator; 6 | import android.content.Context; 7 | import android.content.res.TypedArray; 8 | import android.graphics.Canvas; 9 | import android.graphics.Color; 10 | import android.graphics.Paint; 11 | import android.graphics.Paint.Cap; 12 | import android.graphics.RectF; 13 | import android.util.AttributeSet; 14 | import android.util.Log; 15 | import android.util.Property; 16 | import android.view.View; 17 | import android.view.animation.AccelerateDecelerateInterpolator; 18 | import android.view.animation.Interpolator; 19 | import android.view.animation.LinearInterpolator; 20 | 21 | public class CircularProgress extends View { 22 | 23 | private static final Interpolator ANGLE_INTERPOLATOR = new LinearInterpolator(); 24 | private static final Interpolator SWEEP_INTERPOLATOR = new AccelerateDecelerateInterpolator(); 25 | private static final int ANGLE_ANIMATOR_DURATION = 2000; 26 | private static final int SWEEP_ANIMATOR_DURATION = 900; 27 | private static final int MIN_SWEEP_ANGLE = 30; 28 | private static final int DEFAULT_BORDER_WIDTH = 3; 29 | private final RectF fBounds = new RectF(); 30 | 31 | private ObjectAnimator mObjectAnimatorSweep; 32 | private ObjectAnimator mObjectAnimatorAngle; 33 | private boolean mModeAppearing = true; 34 | private Paint mPaint; 35 | private float mCurrentGlobalAngleOffset; 36 | private float mCurrentGlobalAngle; 37 | private float mCurrentSweepAngle; 38 | private float mBorderWidth; 39 | private boolean mRunning; 40 | private int[] mColors; 41 | private int mCurrentColorIndex; 42 | private int mNextColorIndex; 43 | 44 | public CircularProgress(Context context) { 45 | this(context, null); 46 | } 47 | 48 | public CircularProgress(Context context, AttributeSet attrs) { 49 | this(context, attrs, 0); 50 | } 51 | 52 | public CircularProgress(Context context, AttributeSet attrs, int defStyleAttr) { 53 | super(context, attrs, defStyleAttr); 54 | 55 | float density = context.getResources().getDisplayMetrics().density; 56 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularProgress, defStyleAttr, 0); 57 | mBorderWidth = a.getDimension(R.styleable.CircularProgress_borderWidth, 58 | DEFAULT_BORDER_WIDTH * density); 59 | a.recycle(); 60 | mColors = new int[4]; 61 | mColors[0] = context.getResources().getColor(R.color.red); 62 | mColors[1] = context.getResources().getColor(R.color.yellow); 63 | mColors[2] = context.getResources().getColor(R.color.green); 64 | mColors[3] = context.getResources().getColor(R.color.blue); 65 | mCurrentColorIndex = 0; 66 | mNextColorIndex = 1; 67 | 68 | mPaint = new Paint(); 69 | mPaint.setAntiAlias(true); 70 | mPaint.setStyle(Paint.Style.STROKE); 71 | mPaint.setStrokeCap(Cap.ROUND); 72 | mPaint.setStrokeWidth(mBorderWidth); 73 | mPaint.setColor(mColors[mCurrentColorIndex]); 74 | 75 | setupAnimations(); 76 | } 77 | 78 | private void start() { 79 | if (isRunning()) { 80 | return; 81 | } 82 | mRunning = true; 83 | mObjectAnimatorAngle.start(); 84 | mObjectAnimatorSweep.start(); 85 | invalidate(); 86 | } 87 | 88 | private void stop() { 89 | if (!isRunning()) { 90 | return; 91 | } 92 | mRunning = false; 93 | mObjectAnimatorAngle.cancel(); 94 | mObjectAnimatorSweep.cancel(); 95 | invalidate(); 96 | } 97 | 98 | private boolean isRunning() { 99 | return mRunning; 100 | } 101 | 102 | @Override 103 | protected void onVisibilityChanged(View changedView, int visibility) { 104 | super.onVisibilityChanged(changedView, visibility); 105 | if (visibility == VISIBLE) { 106 | start(); 107 | } else { 108 | stop(); 109 | } 110 | } 111 | 112 | @Override 113 | protected void onAttachedToWindow() { 114 | start(); 115 | super.onAttachedToWindow(); 116 | } 117 | 118 | @Override 119 | protected void onDetachedFromWindow() { 120 | stop(); 121 | super.onDetachedFromWindow(); 122 | } 123 | @Override 124 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 125 | super.onSizeChanged(w, h, oldw, oldh); 126 | fBounds.left = mBorderWidth / 2f + .5f; 127 | fBounds.right = w - mBorderWidth / 2f - .5f; 128 | fBounds.top = mBorderWidth / 2f + .5f; 129 | fBounds.bottom = h - mBorderWidth / 2f - .5f; 130 | } 131 | 132 | @Override 133 | public void draw(Canvas canvas) { 134 | super.draw(canvas); 135 | float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset; 136 | float sweepAngle = mCurrentSweepAngle; 137 | if (mModeAppearing) { 138 | mPaint.setColor(gradient(mColors[mCurrentColorIndex], mColors[mNextColorIndex], 139 | mCurrentSweepAngle / (360 - MIN_SWEEP_ANGLE * 2))); 140 | sweepAngle += MIN_SWEEP_ANGLE; 141 | } else { 142 | startAngle = startAngle + sweepAngle; 143 | sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE; 144 | } 145 | canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint); 146 | } 147 | 148 | private static int gradient(int color1, int color2, float p) { 149 | int r1 = (color1 & 0xff0000) >> 16; 150 | int g1 = (color1 & 0xff00) >> 8; 151 | int b1 = color1 & 0xff; 152 | int r2 = (color2 & 0xff0000) >> 16; 153 | int g2 = (color2 & 0xff00) >> 8; 154 | int b2 = color2 & 0xff; 155 | int newr = (int) (r2 * p + r1 * (1 - p)); 156 | int newg = (int) (g2 * p + g1 * (1 - p)); 157 | int newb = (int) (b2 * p + b1 * (1 - p)); 158 | return Color.argb(255, newr, newg, newb); 159 | } 160 | 161 | private void toggleAppearingMode() { 162 | mModeAppearing = !mModeAppearing; 163 | if (mModeAppearing) { 164 | mCurrentColorIndex = ++mCurrentColorIndex % 4; 165 | mNextColorIndex = ++mNextColorIndex % 4; 166 | mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360; 167 | } 168 | } 169 | // //////////////////////////////////////////////////////////////////////////// 170 | // ////////////// Animation 171 | 172 | private Property mAngleProperty = new Property(Float.class, "angle") { 173 | @Override 174 | public Float get(CircularProgress object) { 175 | return object.getCurrentGlobalAngle(); 176 | } 177 | 178 | @Override 179 | public void set(CircularProgress object, Float value) { 180 | object.setCurrentGlobalAngle(value); 181 | } 182 | }; 183 | 184 | private Property mSweepProperty = new Property(Float.class, "arc") { 185 | @Override 186 | public Float get(CircularProgress object) { 187 | return object.getCurrentSweepAngle(); 188 | } 189 | 190 | @Override 191 | public void set(CircularProgress object, Float value) { 192 | object.setCurrentSweepAngle(value); 193 | } 194 | }; 195 | 196 | private void setupAnimations() { 197 | mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f); 198 | mObjectAnimatorAngle.setInterpolator(ANGLE_INTERPOLATOR); 199 | mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION); 200 | mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART); 201 | mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE); 202 | 203 | mObjectAnimatorSweep = ObjectAnimator.ofFloat(this, mSweepProperty, 360f - MIN_SWEEP_ANGLE * 2); 204 | mObjectAnimatorSweep.setInterpolator(SWEEP_INTERPOLATOR); 205 | mObjectAnimatorSweep.setDuration(SWEEP_ANIMATOR_DURATION); 206 | mObjectAnimatorSweep.setRepeatMode(ValueAnimator.RESTART); 207 | mObjectAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE); 208 | mObjectAnimatorSweep.addListener(new Animator.AnimatorListener() { 209 | @Override 210 | public void onAnimationStart(Animator animation) { 211 | 212 | } 213 | 214 | @Override 215 | public void onAnimationEnd(Animator animation) { 216 | 217 | } 218 | 219 | @Override 220 | public void onAnimationCancel(Animator animation) { 221 | 222 | } 223 | 224 | @Override 225 | public void onAnimationRepeat(Animator animation) { 226 | toggleAppearingMode(); 227 | } 228 | }); 229 | } 230 | 231 | public void setCurrentGlobalAngle(float currentGlobalAngle) { 232 | mCurrentGlobalAngle = currentGlobalAngle; 233 | invalidate(); 234 | } 235 | 236 | public float getCurrentGlobalAngle() { 237 | return mCurrentGlobalAngle; 238 | } 239 | 240 | public void setCurrentSweepAngle(float currentSweepAngle) { 241 | mCurrentSweepAngle = currentSweepAngle; 242 | invalidate(); 243 | } 244 | 245 | public float getCurrentSweepAngle() { 246 | return mCurrentSweepAngle; 247 | } 248 | } 249 | --------------------------------------------------------------------------------