├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── AndroidRotateAnim.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── rotateanim
│ │ └── example
│ │ └── com
│ │ └── androidrotateanim
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── rotateanim
│ │ │ └── example
│ │ │ └── com
│ │ │ └── androidrotateanim
│ │ │ ├── CircleProgressView.java
│ │ │ ├── GradientArcProgressView.java
│ │ │ ├── GradientArcProgressView2.java
│ │ │ ├── GradientArcView.java
│ │ │ ├── Rotate3dAnimation.java
│ │ │ ├── Rotate3dAnimationXY.java
│ │ │ ├── RotateActivity.java
│ │ │ └── RoundNumProgressView.java
│ └── res
│ │ ├── drawable
│ │ ├── test1.jpg
│ │ ├── test2.jpg
│ │ └── test3.jpg
│ │ ├── layout
│ │ ├── activity_rotate.xml
│ │ └── content_rotate.xml
│ │ ├── menu
│ │ └── menu_rotate.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── rotateanim
│ └── example
│ └── com
│ └── androidrotateanim
│ └── ExampleUnitTest.java
├── build.gradle
├── docpic
└── RotateAnim.gif
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AndroidRotateAnim.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidRotateAnim
2 | Android旋转动画+Android圆形进度条组合
3 |
4 | 
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "rotateanim.example.com.androidrotateanim"
9 | minSdkVersion 15
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.1.0'
26 | compile 'com.android.support:design:23.1.0'
27 | }
28 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in H:\android-cmcm-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/rotateanim/example/com/androidrotateanim/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/CircleProgressView.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Matrix;
6 | import android.graphics.Paint;
7 | import android.graphics.SweepGradient;
8 | import android.util.AttributeSet;
9 | import android.util.DisplayMetrics;
10 | import android.util.TypedValue;
11 | import android.view.Surface;
12 | import android.view.SurfaceHolder;
13 | import android.view.SurfaceView;
14 |
15 | /**
16 | * Created by yzs on 2017/7/13.
17 | * 圆形进度控件,在SurfaceView中绘制
18 | */
19 |
20 | public class CircleProgressView extends SurfaceView implements SurfaceHolder.Callback {
21 |
22 | // ================ 公共数据 ============= //
23 | /** 顶部作为计数起点, 右边是0,左边是-180或者180,底部是90 */
24 | private static final int START_POINT_TOP = -90;
25 | private static final float TOTAL_ANGLE = 360f;
26 | private static final int CLEAR_COLOR = 0xff0583f7;
27 |
28 | /** 圆环进度的颜色 */
29 | private int mRoundProgressColor = 0xff04d3ff;
30 | /** 背景颜色 */
31 | private int mRoundProgressBgColor = CLEAR_COLOR;
32 | /** 圆心的x坐标 */
33 | float mCenterX = 0;
34 | /** 圆心的y坐标 */
35 | float mCenterY = 0;
36 | /** 定义画笔 */
37 | private Paint mProgressPaint;
38 | /** SurfaceView的绘制线程 */
39 | private DrawThread mDrawThread;
40 | private SurfaceHolder mSurfaceHolder;
41 | private DisplayMetrics mMetrics;
42 | /** 最大帧数 (1000 / 20) */
43 | private static final int DRAW_INTERVAL = 20;
44 |
45 |
46 | public CircleProgressView(Context context) {
47 | super(context);
48 | init();
49 | }
50 |
51 | public CircleProgressView(Context context, AttributeSet attrs) {
52 | super(context, attrs);
53 | init();
54 | }
55 |
56 | private void init() {
57 | mProgressPaint = new Paint();
58 | mProgressPaint.setAntiAlias(true);
59 | mMetrics = getResources().getDisplayMetrics();
60 | mOuterRoundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, mMetrics);
61 | mOuterHeadCircleWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, mMetrics);
62 |
63 | mSurfaceHolder = getHolder();
64 | mSurfaceHolder.addCallback(this);
65 | }
66 |
67 | private void start() {
68 | if (mDrawThread == null) {
69 | mDrawThread = new DrawThread(mSurfaceHolder, getContext());
70 | }
71 | try {
72 | if (!mDrawThread.isRunning) {
73 | mDrawThread.isRunning = true;
74 | mDrawThread.start();
75 | }
76 | } catch (Exception ignore) {}
77 | }
78 |
79 | private void stop() {
80 | mDrawThread.isRunning = false;
81 | try {
82 | mDrawThread.join();
83 | mDrawThread = null;
84 | } catch (Exception e) {
85 | e.printStackTrace();
86 | }
87 | }
88 |
89 | @Override
90 | public void surfaceCreated(SurfaceHolder holder) {
91 | start();
92 | }
93 |
94 | @Override
95 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
96 |
97 | @Override
98 | public void surfaceDestroyed(SurfaceHolder holder) {
99 | stop();
100 | }
101 |
102 | class DrawThread extends Thread {
103 | SurfaceHolder surfaceHolder;
104 | Context context;
105 | boolean isRunning;
106 |
107 | public DrawThread(SurfaceHolder surfaceHolder, Context context) {
108 | this.surfaceHolder = surfaceHolder;
109 | this.context = context;
110 | }
111 |
112 | @Override
113 | public void run() {
114 | long timeStartPerDraw;
115 | long deltaTime;
116 | while (isRunning) {
117 | Canvas canvas = null;
118 | timeStartPerDraw = System.currentTimeMillis();
119 | try {
120 | synchronized (surfaceHolder) {
121 | Surface surface = surfaceHolder.getSurface();
122 | if (surface != null && surface.isValid()) {
123 | canvas = surfaceHolder.lockCanvas(null);
124 | }
125 | if (canvas != null) {
126 | doDraw(canvas);
127 | }
128 | }
129 | } catch (Exception e) {
130 | e.printStackTrace();
131 | } finally {
132 | if (surfaceHolder != null && canvas != null) {
133 | try {
134 | surfaceHolder.unlockCanvasAndPost(canvas);
135 | } catch (Exception ignore) {}
136 | }
137 | }
138 | deltaTime = System.currentTimeMillis() - timeStartPerDraw;
139 | if (deltaTime < DRAW_INTERVAL) {
140 | try {
141 | // 控制帧数
142 | Thread.sleep(DRAW_INTERVAL - deltaTime);
143 | } catch (Exception e) {
144 | e.printStackTrace();
145 | }
146 | }
147 | }
148 | }
149 | }
150 |
151 |
152 | private void doDraw(Canvas canvas) {
153 | calculatePreValue();
154 | canvas.drawColor(mRoundProgressBgColor);
155 | drawProgressPart(canvas);
156 | }
157 |
158 | private int mProgressAlpha = 255;
159 | private void drawProgressPart(Canvas canvas) {
160 | drawOuterGradientProgress(canvas);
161 | }
162 |
163 | private void calculatePreValue() {
164 | if (mCenterX <= 0) {
165 | mCenterX = getWidth() / 2; // 获取圆心的x坐标
166 | }
167 | if (mCenterY <= 0) {
168 | mCenterY = getHeight() / 2;
169 | }
170 | if (mOuterRadius <= 0) {
171 | mOuterRadius = getWidth() / 2 - mOuterRoundWidth;
172 | }
173 | }
174 |
175 | // ================ 外环进度数据 ============= //
176 | /** 顶部作为计数起点 270度, 计算圆上的任意点坐标时顺时针为正,右边是0 */
177 | private static final float HEAD_CIRCLE_START_ANGLE = 270f;
178 | /** 进度条每次移动的角度 */
179 | private static int mOuterProgressStep = 8;
180 | /** 修改这个颜色数组就会出现不一样的渐变圆弧 */
181 | private int[] mColors = {
182 | 0x0004d3ff, 0x0004d3ff, 0x4004d3ff, 0x8004d3ff, 0xff04d3ff
183 | };
184 | /** 外环渐变处理器 */
185 | private SweepGradient mOuterSweepGradient;
186 | /** 外环用于旋转的矩阵 Matrix */
187 | private Matrix mOuterMatrix = new Matrix();
188 | /** 外圆环的宽度 */
189 | private float mOuterRoundWidth;
190 | /** 外圆环头部的圆圈半径 */
191 | private float mOuterHeadCircleWidth;
192 | /** 外环的半径 */
193 | private float mOuterRadius = 0;
194 | /** 外环角度旋转总进度*/
195 | private float mOuterAngleProgressTotal = 0;
196 | /** 外环头部圆选择角度 */
197 | private float mOuterHeadCircleAngleTotal = 0;
198 | private double mOuterHeadCircleAngleTotalMath = 0;
199 | private void drawOuterGradientProgress(final Canvas canvas) {
200 | mProgressPaint.setStrokeWidth(mOuterRoundWidth); // 设置圆环的宽度
201 | mProgressPaint.setColor(mRoundProgressColor); // 设置进度的颜色
202 | mProgressPaint.setAlpha(mProgressAlpha);
203 | mProgressPaint.setStyle(Paint.Style.STROKE);
204 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
205 | if (mOuterSweepGradient == null) {
206 | mOuterSweepGradient = new SweepGradient(mCenterX, mCenterY, mColors, null);
207 | }
208 | mOuterMatrix.setRotate((START_POINT_TOP + mOuterAngleProgressTotal), mCenterX, mCenterY);
209 | mOuterSweepGradient.setLocalMatrix(mOuterMatrix);
210 | mProgressPaint.setShader(mOuterSweepGradient);
211 | canvas.drawCircle(mCenterX, mCenterY, mOuterRadius, mProgressPaint); // 画出圆环
212 | drawOuterArcHeadCircle(canvas);
213 | mOuterAngleProgressTotal += mOuterProgressStep;
214 | if (mOuterAngleProgressTotal > TOTAL_ANGLE) {
215 | mOuterAngleProgressTotal -= TOTAL_ANGLE;
216 | }
217 | }
218 |
219 | private void drawOuterArcHeadCircle(final Canvas canvas) {
220 | mProgressPaint.setShader(null);
221 | mProgressPaint.setStrokeWidth(0);
222 | mProgressPaint.setStyle(Paint.Style.FILL);
223 | // 一开始从顶部开始旋转
224 | mOuterHeadCircleAngleTotal = (HEAD_CIRCLE_START_ANGLE + mOuterAngleProgressTotal);
225 | if (mOuterHeadCircleAngleTotal - TOTAL_ANGLE > 0) {
226 | mOuterHeadCircleAngleTotal -= TOTAL_ANGLE;
227 | }
228 | // 根据旋转角度计算圆上当前位置点坐标,再以当前位置左边点位圆心画一个圆
229 | mOuterHeadCircleAngleTotalMath = mOuterHeadCircleAngleTotal * Math.PI / 180f;
230 | canvas.drawCircle((float) (mCenterX + mOuterRadius * Math.cos(mOuterHeadCircleAngleTotalMath)),
231 | (float) (mCenterY + mOuterRadius * Math.sin(mOuterHeadCircleAngleTotalMath)),
232 | mOuterHeadCircleWidth, mProgressPaint);
233 | }
234 |
235 | public void setProgressColors(int colors[]) {
236 | mColors = colors;
237 | mRoundProgressColor = mColors[mColors.length - 1];
238 | }
239 |
240 | public void setRoundProgressBgColor(int roundProgressBgColor) {
241 | mRoundProgressBgColor = roundProgressBgColor;
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/GradientArcProgressView.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.SweepGradient;
10 | import android.util.AttributeSet;
11 | import android.util.DisplayMetrics;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 |
15 | /**
16 | * 渐变圆弧实现进度条-这里使用画整个圆的方式来实现
17 | */
18 | public class GradientArcProgressView extends View {
19 |
20 | private static final int ROUND_COLOR_DEFAULT = 0x33ffffff;
21 | private static final int ROUND_WIDTH_DEFAULT = 2; //dp
22 | private static final int ROUND_PROGRESS_COLOR_DEFAULT = 0xffffffff;
23 |
24 | /** 进度条每次移动的角度 */
25 | private static final int FLICKER_PROGRESS_STEP = 10;
26 | /** 顶部作为计数起点, 右边是0,左边是-180或者180,底部是90 */
27 | private static final int START_POINT_TOP = -90;
28 |
29 | /** 定义一支画笔 */
30 | private Paint mPaint;
31 | private Paint mGradientArcPaint;
32 | private SweepGradient mSweepGradient;
33 | /** 修改这个颜色数组就会出现不一样的渐变圆弧 */
34 | private int[] mColors = {
35 | 0x00ffffff, 0x40ffffff, 0x80ffffff, Color.WHITE
36 | };
37 | private Matrix mMatrix = new Matrix();
38 | /** 圆环的颜色 */
39 | private int mRoundColor;
40 | /** 圆环的宽度 */
41 | private float mRoundWidth;
42 | /** 圆环进度的颜色 */
43 | private int mRoundProgressColor;
44 |
45 | /** 进度的风格,实心(FILL)或者空心(STROKE) */
46 | private int mStyle;
47 | public static final int STROKE = 0;
48 | public static final int FILL = 1;
49 |
50 | /** 进度旋转方向,顺时针(CLOCKWISE)或者逆时针(COUNTERCLOCKWISE) */
51 | private int mRotateOrientation;
52 | public static final int COUNTERCLOCKWISE = 0;
53 | public static final int CLOCKWISE = 1;
54 |
55 | private int mFlickerProgressTotal = 0;
56 |
57 | /** 闪烁进度条动画正在进行 */
58 | private boolean isFlickerProgressWorking = false;
59 |
60 | public GradientArcProgressView(Context context) {
61 | this(context, null);
62 | }
63 |
64 | public GradientArcProgressView(Context context, AttributeSet attrs) {
65 | this(context, attrs, 0);
66 | }
67 |
68 | public GradientArcProgressView(Context context, AttributeSet attrs, int defStyle) {
69 | super(context, attrs, defStyle);
70 | mPaint = new Paint();
71 | mGradientArcPaint = new Paint();
72 | //获取自定义属性和默认值
73 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundNumProgressView);
74 | mRoundColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundColor, ROUND_COLOR_DEFAULT);
75 | mRoundProgressColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundProgressColor, ROUND_PROGRESS_COLOR_DEFAULT);
76 |
77 | final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
78 | mRoundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ROUND_WIDTH_DEFAULT, metrics);
79 | mStyle = mTypedArray.getInt(R.styleable.RoundNumProgressView_style, STROKE);
80 | mRotateOrientation = CLOCKWISE;
81 | mTypedArray.recycle();
82 | }
83 |
84 | int centerX = 0; // 获取圆心的x坐标
85 | int radius =0; // 圆环的半径
86 | @Override
87 | protected void onDraw(Canvas canvas) {
88 | super.onDraw(canvas);
89 | if (centerX == 0) {
90 | centerX = getWidth() / 2; // 获取圆心的x坐标
91 | }
92 | if (radius == 0) {
93 | radius = (int) (centerX - mRoundWidth / 2); // 圆环的半径
94 | }
95 | // 画最外层的大圆环
96 | drawOuterCircle(canvas, centerX, radius);
97 | // 画闪烁的进度条动画
98 | if (isFlickerProgressWorking) {
99 | drawFlickerArcProgress(canvas, centerX, radius);
100 | } else {
101 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
102 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
103 | mGradientArcPaint.setAntiAlias(true);
104 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
105 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
106 | if (mSweepGradient == null)
107 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
108 | mMatrix.setRotate(START_POINT_TOP, centerX, centerX);
109 | mSweepGradient.setLocalMatrix(mMatrix);
110 | mGradientArcPaint.setShader(mSweepGradient);
111 | canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
112 | }
113 | }
114 |
115 | private void drawOuterCircle(final Canvas canvas, final int centerX, final int radius) {
116 | mPaint.setColor(mRoundColor); // 设置圆环的颜色
117 | mPaint.setStyle(Paint.Style.STROKE); // 设置空心
118 | mPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
119 | mPaint.setAntiAlias(true); // 消除锯齿
120 | canvas.drawCircle(centerX, centerX, radius, mPaint); // 画出圆环
121 | }
122 |
123 | private void drawFlickerArcProgress(final Canvas canvas, final int centerX, final int radius) {
124 | drawGradientCircle(canvas, centerX, radius);
125 | post(new Runnable() {
126 | @Override
127 | public void run() {
128 | mFlickerProgressTotal += FLICKER_PROGRESS_STEP;
129 | postInvalidate();
130 | }
131 | });
132 | }
133 |
134 | private void drawGradientCircle(final Canvas canvas, final int centerX, final int radius) {
135 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
136 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
137 | mGradientArcPaint.setAntiAlias(true);
138 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
139 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
140 | if (mSweepGradient == null) {
141 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
142 | }
143 | if (mRotateOrientation == COUNTERCLOCKWISE) { // 计数起点在顶部,所以为-90
144 | mMatrix.setRotate((START_POINT_TOP - mFlickerProgressTotal) % 360, centerX, centerX);
145 | } else if (mRotateOrientation == CLOCKWISE) {
146 | mMatrix.setRotate((START_POINT_TOP + mFlickerProgressTotal) % 360, centerX, centerX);
147 | }
148 | mSweepGradient.setLocalMatrix(mMatrix);
149 | mGradientArcPaint.setShader(mSweepGradient);
150 | canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
151 | }
152 |
153 | /***
154 | * 启动闪烁动画,点击的时候调用会起到很好的提示作用
155 | */
156 | public void startFlickerArcProgress(final Runnable endFlagRunnable) {
157 | if (isFlickerProgressWorking)
158 | return;
159 | isFlickerProgressWorking = true;
160 | postInvalidate();
161 | }
162 |
163 | public void setStyle(int style) {
164 | mStyle = style;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/GradientArcProgressView2.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.SweepGradient;
11 | import android.util.AttributeSet;
12 | import android.util.DisplayMetrics;
13 | import android.util.TypedValue;
14 | import android.view.View;
15 |
16 | /**
17 | * 渐变圆弧实现进度条-这个才用画圆弧的方式来实现
18 | */
19 | public class GradientArcProgressView2 extends View {
20 |
21 | private static final int ROUND_COLOR_DEFAULT = 0x33ffffff;
22 | private static final int ROUND_WIDTH_DEFAULT = 2; //dp
23 | private static final int ROUND_PROGRESS_COLOR_DEFAULT = 0xffffffff;
24 |
25 | /** 闪烁进度条每次移动的角度 */
26 | private static final int FLICKER_PROGRESS_STEP = 10;
27 | /** 顶部作为计数起点, 右边是0,左边是-180或者180,底部是90 */
28 | private static final int START_POINT_TOP = -90;
29 |
30 | /** 弧长及方向 */
31 | private static final int ARC_LENGTH = -180;
32 |
33 | /** 定义一支画笔 */
34 | private Paint mPaint;
35 | private Paint mGradientArcPaint;
36 | private SweepGradient mSweepGradient;
37 | /** 修改这个颜色数组就会出现不一样的渐变圆弧 */
38 | private int[] mColors = {
39 | 0x00ffffff, 0x40ffffff, 0x80ffffff, Color.WHITE
40 | };
41 | private Matrix mMatrix = new Matrix();
42 | /** 圆环的颜色 */
43 | private int mRoundColor;
44 | /** 圆环的宽度 */
45 | private float mRoundWidth;
46 | /** 圆环进度的颜色 */
47 | private int mRoundProgressColor;
48 | /** 用于定义的圆弧的形状和大小的界限 */
49 | private RectF mArcLimitRect = new RectF();
50 |
51 | /** 进度的风格,实心(FILL)或者空心(STROKE) */
52 | private int mStyle;
53 | public static final int STROKE = 0;
54 | public static final int FILL = 1;
55 |
56 | /** 进度旋转方向,顺时针(CLOCKWISE)或者逆时针(COUNTERCLOCKWISE) */
57 | private int mRotateOrientation;
58 | public static final int COUNTERCLOCKWISE = 0;
59 | public static final int CLOCKWISE = 1;
60 |
61 | private int mFlickerProgressTotal = 0;
62 |
63 | /** 闪烁进度条动画正在进行 */
64 | private boolean isFlickerProgressWorking = false;
65 |
66 | public GradientArcProgressView2(Context context) {
67 | this(context, null);
68 | }
69 |
70 | public GradientArcProgressView2(Context context, AttributeSet attrs) {
71 | this(context, attrs, 0);
72 | }
73 |
74 | public GradientArcProgressView2(Context context, AttributeSet attrs, int defStyle) {
75 | super(context, attrs, defStyle);
76 | mPaint = new Paint();
77 | mGradientArcPaint = new Paint();
78 | //获取自定义属性和默认值
79 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundNumProgressView);
80 | mRoundColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundColor, ROUND_COLOR_DEFAULT);
81 | mRoundProgressColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundProgressColor, ROUND_PROGRESS_COLOR_DEFAULT);
82 |
83 | final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
84 | mRoundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ROUND_WIDTH_DEFAULT, metrics);
85 | mStyle = mTypedArray.getInt(R.styleable.RoundNumProgressView_style, STROKE);
86 | mRotateOrientation = CLOCKWISE;
87 | mTypedArray.recycle();
88 | }
89 |
90 | int centerX = 0; // 获取圆心的x坐标
91 | int radius =0; // 圆环的半径
92 | @Override
93 | protected void onDraw(Canvas canvas) {
94 | super.onDraw(canvas);
95 | if (centerX == 0) {
96 | centerX = getWidth() / 2; // 获取圆心的x坐标
97 | }
98 | if (radius == 0) {
99 | radius = (int) (centerX - mRoundWidth / 2); // 圆环的半径
100 | }
101 | // 画最外层的大圆环
102 | drawOuterCircle(canvas, centerX, radius);
103 | // 画闪烁的进度条动画
104 | if (isFlickerProgressWorking) {
105 | drawFlickerArcProgress(canvas, centerX, radius);
106 | } else {
107 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
108 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
109 | mGradientArcPaint.setAntiAlias(true);
110 | if (mArcLimitRect.isEmpty()) {
111 | mArcLimitRect.set(centerX - radius, centerX - radius, centerX + radius, centerX + radius);
112 | }
113 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
114 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
115 | if (mSweepGradient == null)
116 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
117 | mMatrix.setRotate(START_POINT_TOP, centerX, centerX);
118 | mSweepGradient.setLocalMatrix(mMatrix);
119 | mGradientArcPaint.setShader(mSweepGradient);
120 | canvas.drawArc(mArcLimitRect, START_POINT_TOP, ARC_LENGTH, false, mGradientArcPaint);
121 | // canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
122 | }
123 | }
124 |
125 | private void drawOuterCircle(final Canvas canvas, final int centerX, final int radius) {
126 | mPaint.setColor(mRoundColor); // 设置圆环的颜色
127 | mPaint.setStyle(Paint.Style.STROKE); // 设置空心
128 | mPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
129 | mPaint.setAntiAlias(true); // 消除锯齿
130 | canvas.drawCircle(centerX, centerX, radius, mPaint); // 画出圆环
131 | }
132 |
133 | private void drawFlickerArcProgress(final Canvas canvas, final int centerX, final int radius) {
134 | drawGradientCircle(canvas, centerX, radius);
135 | post(new Runnable() {
136 | @Override
137 | public void run() {
138 | mFlickerProgressTotal += FLICKER_PROGRESS_STEP;
139 | postInvalidate();
140 | }
141 | });
142 | }
143 |
144 | private void drawGradientCircle(final Canvas canvas, final int centerX, final int radius) {
145 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
146 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
147 | mGradientArcPaint.setAntiAlias(true);
148 | if (mArcLimitRect.isEmpty()) {
149 | mArcLimitRect.set(centerX - radius, centerX - radius, centerX + radius, centerX + radius);
150 | }
151 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
152 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
153 | if (mSweepGradient == null) {
154 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
155 | }
156 | if (mRotateOrientation == COUNTERCLOCKWISE) { // 计数起点在顶部,所以为-90
157 | mMatrix.setRotate((START_POINT_TOP - mFlickerProgressTotal) % 360, centerX, centerX);
158 | } else if (mRotateOrientation == CLOCKWISE) {
159 | mMatrix.setRotate((START_POINT_TOP + mFlickerProgressTotal) % 360, centerX, centerX);
160 | }
161 | mSweepGradient.setLocalMatrix(mMatrix);
162 | mGradientArcPaint.setShader(mSweepGradient);
163 | canvas.drawArc(mArcLimitRect, (START_POINT_TOP + mFlickerProgressTotal) % 360, ARC_LENGTH, false, mGradientArcPaint);
164 | // canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
165 | }
166 |
167 | /***
168 | * 启动闪烁动画,点击的时候调用会起到很好的提示作用
169 | */
170 | public void startFlickerArcProgress(final Runnable endFlagRunnable) {
171 | if (isFlickerProgressWorking)
172 | return;
173 | isFlickerProgressWorking = true;
174 | postInvalidate();
175 | }
176 |
177 | public void setStyle(int style) {
178 | mStyle = style;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/GradientArcView.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.SweepGradient;
10 | import android.util.AttributeSet;
11 | import android.util.DisplayMetrics;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 |
15 | import java.util.Iterator;
16 | import java.util.Vector;
17 |
18 | /**
19 | * 渐变圆弧
20 | */
21 | public class GradientArcView extends View {
22 |
23 | private static final int ROUND_COLOR_DEFAULT = 0x33ffffff;
24 | private static final int ROUND_WIDTH_DEFAULT = 2; //dp
25 | private static final int ROUND_PROGRESS_COLOR_DEFAULT = 0xffffffff;
26 |
27 | /** 闪烁进度条每次移动的角度 */
28 | private static final int FLICKER_PRORESS_STEP = 40;
29 | /** 顶部作为计数起点, 右边是0,左边是-180或者180,底部是90 */
30 | private static final int START_POINT_TOP = -90;
31 |
32 | /** 定义一支画笔 */
33 | private Paint mPaint;
34 | private Paint mGradientArcPaint;
35 | private SweepGradient mSweepGradient;
36 | private int[] mColors = {
37 | 0x00ffffff, 0x40ffffff, 0x80ffffff, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, 0x80ffffff, 0x40ffffff, 0x00ffffff
38 | };
39 | private Matrix mMatrix = new Matrix();
40 | /** 圆环的颜色 */
41 | private int mRoundColor;
42 | /** 圆环的宽度 */
43 | private float mRoundWidth;
44 | /** 圆环进度的颜色 */
45 | private int mRoundProgressColor;
46 |
47 | /** 进度旋转方向,顺时针(CLOCKWISE)或者逆时针(COUNTERCLOCKWISE) */
48 | private int mRotateOrientation;
49 | public static final int COUNTERCLOCKWISE = 0;
50 | public static final int CLOCKWISE = 1;
51 |
52 | /** 闪烁(循环旋转)进度条的时间 */
53 | private int mFlickerProgressTime = 1000;
54 | private int mFlickerProgressTotal = 0;
55 |
56 | /** 闪烁进度条动画正在进行 */
57 | private boolean isFlickerProgressWorking = false;
58 |
59 | private Vector mRoundNumProgressListeners;
60 |
61 | public interface IRoundNumProgressListener {
62 | void onFlickerProgressEnd();
63 | }
64 |
65 | public GradientArcView(Context context) {
66 | this(context, null);
67 | }
68 |
69 | public GradientArcView(Context context, AttributeSet attrs) {
70 | this(context, attrs, 0);
71 | }
72 |
73 | public GradientArcView(Context context, AttributeSet attrs, int defStyle) {
74 | super(context, attrs, defStyle);
75 | mPaint = new Paint();
76 | mGradientArcPaint = new Paint();
77 | //获取自定义属性和默认值
78 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundNumProgressView);
79 | mRoundColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundColor, ROUND_COLOR_DEFAULT);
80 | mRoundProgressColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundProgressColor, ROUND_PROGRESS_COLOR_DEFAULT);
81 |
82 | final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
83 | mRoundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ROUND_WIDTH_DEFAULT, metrics);
84 | mRotateOrientation = CLOCKWISE;
85 | mTypedArray.recycle();
86 | }
87 |
88 | public void addRoundNumProgressListener(IRoundNumProgressListener roundNumProgressListener) {
89 | if (roundNumProgressListener == null)
90 | return;
91 | if (mRoundNumProgressListeners == null) {
92 | mRoundNumProgressListeners = new Vector();
93 | }
94 | mRoundNumProgressListeners.add(roundNumProgressListener);
95 | }
96 |
97 | private void notifyAllRoundNumProressListeners() {
98 | if (mRoundNumProgressListeners == null)
99 | return;
100 | Iterator iterator = mRoundNumProgressListeners.iterator();
101 | while (iterator.hasNext()) {
102 | iterator.next().onFlickerProgressEnd();
103 | }
104 | }
105 |
106 | int centerX = 0; // 获取圆心的x坐标
107 | int radius =0; // 圆环的半径
108 | @Override
109 | protected void onDraw(Canvas canvas) {
110 | super.onDraw(canvas);
111 | if (centerX == 0) {
112 | centerX = getWidth() / 2; // 获取圆心的x坐标
113 | }
114 | if (radius == 0) {
115 | radius = (int) (centerX - mRoundWidth / 2); // 圆环的半径
116 | }
117 | // 画最外层的大圆环
118 | drawOuterCircle(canvas, centerX, radius);
119 | // 画闪烁的进度条动画
120 | if (isFlickerProgressWorking) {
121 | drawFlickerArcProgress(canvas, centerX, radius);
122 | } else {
123 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
124 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
125 | mGradientArcPaint.setAntiAlias(true);
126 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
127 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
128 | if (mSweepGradient == null)
129 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
130 | mMatrix.setRotate(START_POINT_TOP, centerX, centerX);
131 | mSweepGradient.setLocalMatrix(mMatrix);
132 | mGradientArcPaint.setShader(mSweepGradient);
133 | canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
134 | }
135 | }
136 |
137 | private void drawOuterCircle(final Canvas canvas, final int centerX, final int radius) {
138 | mPaint.setColor(mRoundColor); // 设置圆环的颜色
139 | mPaint.setStyle(Paint.Style.STROKE); // 设置空心
140 | mPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
141 | mPaint.setAntiAlias(true); // 消除锯齿
142 | canvas.drawCircle(centerX, centerX, radius, mPaint); // 画出圆环
143 | }
144 |
145 | private void drawFlickerArcProgress(final Canvas canvas, final int centerX, final int radius) {
146 | drawGradientCircle(canvas, centerX, radius);
147 | post(new Runnable() {
148 | @Override
149 | public void run() {
150 | mFlickerProgressTotal += FLICKER_PRORESS_STEP;
151 | postInvalidate();
152 | }
153 | });
154 | }
155 |
156 | private void drawGradientCircle(final Canvas canvas, final int centerX, final int radius) {
157 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
158 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
159 | mGradientArcPaint.setAntiAlias(true);
160 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
161 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
162 | if (mSweepGradient == null) {
163 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
164 | }
165 | if (mRotateOrientation == COUNTERCLOCKWISE) { // 计数起点在顶部,所以为-90
166 | mMatrix.setRotate(START_POINT_TOP - mFlickerProgressTotal, centerX, centerX);
167 | } else if (mRotateOrientation == CLOCKWISE) {
168 | mMatrix.setRotate(START_POINT_TOP + mFlickerProgressTotal, centerX, centerX);
169 | }
170 | mSweepGradient.setLocalMatrix(mMatrix);
171 | mGradientArcPaint.setShader(mSweepGradient);
172 | canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
173 | }
174 |
175 | /***
176 | * 启动闪烁动画,点击的时候调用会起到很好的提示作用
177 | */
178 | public void startFlickerArcProgress(final Runnable endFlagRunnable) {
179 | if (isFlickerProgressWorking)
180 | return;
181 | isFlickerProgressWorking = true;
182 | postInvalidate();
183 | postDelayed(new Runnable() {
184 | @Override
185 | public void run() {
186 | isFlickerProgressWorking = false;
187 | postInvalidate();
188 | if (endFlagRunnable != null) {
189 | endFlagRunnable.run();
190 | }
191 | notifyAllRoundNumProressListeners();
192 | }
193 | }, mFlickerProgressTime);
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/Rotate3dAnimation.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.view.animation.Animation;
4 | import android.view.animation.Transformation;
5 | import android.graphics.Camera;
6 | import android.graphics.Matrix;
7 |
8 | /**
9 | * An animation that rotates the view on the X,Y,Z axis between two specified angles.
10 | * This animation also adds a translation on the Z axis (depth) to improve the effect.
11 | */
12 | public class Rotate3dAnimation extends Animation {
13 | public static final Byte ROTATE_X_AXIS = 0x00;
14 | public static final Byte ROTATE_Y_AXIS = 0x01;
15 | public static final Byte ROTATE_Z_AXIS = 0x02;
16 | private final float mFromDegrees;
17 | private final float mToDegrees;
18 | private final float mCenterX;
19 | private final float mCenterY;
20 | private final float mDepthZ;
21 | private final boolean mReverse;
22 | private Camera mCamera;
23 | private Byte mRotateAxis; // 0:X轴 1:Y轴 2:Z轴
24 |
25 | /**创建3D旋转动画
26 | * @param fromDegrees the start angle of the 3D rotation
27 | * @param toDegrees the end angle of the 3D rotation
28 | * @param centerX the X center of the 3D rotation
29 | * @param centerY the Y center of the 3D rotation
30 | * @param depthZ the Z depth of the 3D rotation
31 | * @param rotateAxis the rotate axis of the 3D rotation
32 | * @param reverse true if the translation should be reversed, false otherwise
33 | */
34 | public Rotate3dAnimation(float fromDegrees, float toDegrees,
35 | float centerX, float centerY, float depthZ, Byte rotateAxis, boolean reverse) {
36 | mFromDegrees = fromDegrees;
37 | mToDegrees = toDegrees;
38 | mCenterX = centerX;
39 | mCenterY = centerY;
40 | mDepthZ = depthZ;
41 | mRotateAxis = rotateAxis;
42 | mReverse = reverse;
43 | }
44 |
45 | @Override
46 | public void initialize(int width, int height, int parentWidth, int parentHeight) {
47 | super.initialize(width, height, parentWidth, parentHeight);
48 | mCamera = new Camera();
49 | }
50 |
51 | @Override
52 | protected void applyTransformation(float interpolatedTime, Transformation t) {
53 | final float fromDegrees = mFromDegrees;
54 | float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
55 |
56 | final float centerX = mCenterX;
57 | final float centerY = mCenterY;
58 | final Camera camera = mCamera;
59 |
60 | final Matrix matrix = t.getMatrix();
61 | // 将当前的摄像头位置保存下来,以便变换进行完成后恢复成原位
62 | camera.save();
63 | if (mReverse) {
64 | // z的偏移会越来越大。这就会形成这样一个效果,view从近到远
65 | camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
66 | } else {
67 | // z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,最终移到了我们的窗口上面
68 | camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
69 | }
70 | // 是给我们的View加上旋转效果,在移动的过程中,视图还会以XYZ轴为中心进行旋转。
71 | if (ROTATE_X_AXIS.equals(mRotateAxis)) {
72 | camera.rotateX(degrees);
73 | } else if (ROTATE_Y_AXIS.equals(mRotateAxis)) {
74 | camera.rotateY(degrees);
75 | } else {
76 | camera.rotateZ(degrees);
77 | }
78 |
79 | // 这个是将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用。
80 | camera.getMatrix(matrix);
81 | // camera位置恢复
82 | camera.restore();
83 |
84 | // 下面两句是为了动画是以View中心为旋转点
85 | matrix.preTranslate(-centerX, -centerY);
86 | matrix.postTranslate(centerX, centerY);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/Rotate3dAnimationXY.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package rotateanim.example.com.androidrotateanim;
18 |
19 | import android.view.animation.Animation;
20 | import android.view.animation.Transformation;
21 | import android.graphics.Camera;
22 | import android.graphics.Matrix;
23 |
24 | /**
25 | * An animation that rotates the view on the Y axis between two specified angles.
26 | * This animation also adds a translation on the Z axis (depth) to improve the effect.
27 | */
28 | public class Rotate3dAnimationXY extends Animation {
29 | private final float mFromDegrees;
30 | private final float mToDegrees;
31 | private final float mCenterX;
32 | private final float mCenterY;
33 | private final float mDepthZ;
34 | private final boolean mReverse;
35 | private Camera mCamera;
36 | private byte mRotateXOrY = 0;
37 |
38 | /**
39 | * Creates a new 3D rotation on the Y axis. The rotation is defined by its
40 | * start angle and its end angle. Both angles are in degrees. The rotation
41 | * is performed around a center point on the 2D space, definied by a pair
42 | * of X and Y coordinates, called centerX and centerY. When the animation
43 | * starts, a translation on the Z axis (depth) is performed. The length
44 | * of the translation can be specified, as well as whether the translation
45 | * should be reversed in time.
46 | *
47 | * @param fromDegrees the start angle of the 3D rotation
48 | * @param toDegrees the end angle of the 3D rotation
49 | * @param centerX the X center of the 3D rotation
50 | * @param centerY the Y center of the 3D rotation
51 | * @param reverse true if the translation should be reversed, false otherwise
52 | */
53 | public Rotate3dAnimationXY(float fromDegrees, float toDegrees,
54 | float centerX, float centerY, float depthZ, boolean reverse , byte rotate) {
55 | mFromDegrees = fromDegrees;
56 | mToDegrees = toDegrees;
57 | mCenterX = centerX;
58 | mCenterY = centerY;
59 | mDepthZ = depthZ;
60 | mReverse = reverse;
61 | mRotateXOrY = rotate;
62 | }
63 |
64 | @Override
65 | public void initialize(int width, int height, int parentWidth, int parentHeight) {
66 | super.initialize(width, height, parentWidth, parentHeight);
67 | mCamera = new Camera();
68 | }
69 |
70 | @Override
71 | protected void applyTransformation(float interpolatedTime, Transformation t) {
72 | final float fromDegrees = mFromDegrees;
73 | float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
74 |
75 | final float centerX = mCenterX;
76 | final float centerY = mCenterY;
77 | final Camera camera = mCamera;
78 |
79 | final Matrix matrix = t.getMatrix();
80 | // 将当前的摄像头位置保存下来,以便变换进行完成后恢复成原位
81 | camera.save();
82 |
83 | // camera.translate,这个方法接受3个参数,分别是x,y,z三个轴的偏移量,我们这里只将z轴进行了偏移
84 | if (mReverse) {
85 | // z的偏移会越来越大。这就会形成这样一个效果,view从近到远
86 | camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
87 | } else {
88 | // z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,最终移到了我们的窗口上面
89 | camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
90 | }
91 |
92 | switch (mRotateXOrY) {
93 | case 0:
94 | // 是给我们的View加上旋转效果,在移动的过程中,视图还会移X轴为中心进行旋转。
95 | camera.rotateX(degrees);
96 | break;
97 |
98 | case 1:
99 | // 是给我们的View加上旋转效果,在移动的过程中,视图还会移X轴为中心进行旋转。
100 | camera.rotateY(degrees);
101 | break;
102 | }
103 |
104 | // 这个是将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用。
105 | camera.getMatrix(matrix);
106 | // camera位置恢复
107 | camera.restore();
108 |
109 | float fAlphaRate = 0.2f;
110 | // 改变翻转时的透明度
111 | if (!mReverse)
112 | t.setAlpha(fAlphaRate + (1.0f-fAlphaRate)* interpolatedTime );
113 | else
114 | t.setAlpha(1.0f - fAlphaRate* interpolatedTime );
115 |
116 | // 以View的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
117 | matrix.preTranslate(-centerX, -centerY);
118 | matrix.postTranslate(centerX, centerY);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/RotateActivity.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.os.Bundle;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.util.DisplayMetrics;
11 | import android.util.TypedValue;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.Button;
17 | import android.widget.ImageView;
18 | import android.widget.LinearLayout;
19 |
20 | public class RotateActivity extends AppCompatActivity {
21 |
22 | private ImageView mRotateImgv;
23 | private Button mSwitchAnimBtn1;
24 | private Button mSwitchAnimBtn2;
25 | private Button mSwitchAnimBtn3;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_rotate);
31 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
32 | setSupportActionBar(toolbar);
33 |
34 | // FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
35 | // fab.setOnClickListener(new View.OnClickListener() {
36 | // @Override
37 | // public void onClick(View view) {
38 | // Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
39 | // .setAction("Action", null).show();
40 | // }
41 | // });
42 |
43 | initViewAndListener();
44 | }
45 |
46 | private void initViewAndListener() {
47 | mRotateImgv = (ImageView) findViewById(R.id.rotateview);
48 | mSwitchAnimBtn1 = (Button) findViewById(R.id.rotateanim_btn1);
49 | mSwitchAnimBtn2 = (Button) findViewById(R.id.rotateanim_btn2);
50 | mSwitchAnimBtn3 = (Button) findViewById(R.id.rotateanim_btn3);
51 | mSwitchAnimBtn1.setOnClickListener(new View.OnClickListener() {
52 | @Override
53 | public void onClick(View v) {
54 | rotateAnimHorizon();
55 | }
56 | });
57 | mSwitchAnimBtn2.setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View v) {
60 | rotateOnXCoordinate();
61 | }
62 | });
63 | mSwitchAnimBtn3.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | rotateOnYCoordinate();
67 | }
68 | });
69 |
70 | initRoundNumProgressViews();
71 | }
72 |
73 | private int mCurPic = 0;
74 | private Runnable mEndFlagRunnable = new Runnable() {
75 | @Override
76 | public void run() {
77 | mRotateImgv.postDelayed(new Runnable() {
78 | @Override
79 | public void run() {
80 | mCurPic = mCurPic % 3;
81 | switch (mCurPic) {
82 | case 0:
83 | mRotateImgv.setImageResource(R.drawable.test1);
84 | break;
85 | case 1:
86 | mRotateImgv.setImageResource(R.drawable.test2);
87 | break;
88 | case 2:
89 | mRotateImgv.setImageResource(R.drawable.test3);
90 | break;
91 | }
92 | mCurPic ++;
93 | }
94 | }, 50);
95 | }
96 | };
97 |
98 | private void initRoundNumProgressViews() {
99 | DisplayMetrics metrics = getResources().getDisplayMetrics();
100 | final int numProgressView1Size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, metrics);
101 | final int numProgressView2Size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, metrics);
102 |
103 | final RoundNumProgressView numProgressView = (RoundNumProgressView) findViewById(R.id.roundnumprogressview);
104 | numProgressView.setOnClickListener(new View.OnClickListener() {
105 | @Override
106 | public void onClick(View v) {
107 | numProgressView.setCurProgress(10);
108 | numProgressView.startFlickerArcProgress(mEndFlagRunnable);
109 | }
110 | });
111 | LinearLayout parent = (LinearLayout) findViewById(R.id.proress_parent);
112 | final RoundNumProgressView numProgressView1 = new RoundNumProgressView(getBaseContext());
113 | numProgressView1.setLayoutParams(new ViewGroup.LayoutParams(numProgressView1Size, numProgressView1Size));
114 | parent.addView(numProgressView1);
115 | ((LinearLayout.LayoutParams) numProgressView1.getLayoutParams()).leftMargin = 30;
116 | numProgressView1.setOnClickListener(new View.OnClickListener() {
117 | @Override
118 | public void onClick(View v) {
119 | numProgressView1.setCurProgress(50);
120 | numProgressView1.reRefreshToOriginProgress();
121 | }
122 | });
123 | final RoundNumProgressView numProgressView2 = new RoundNumProgressView(getBaseContext());
124 | numProgressView2.setLayoutParams(new ViewGroup.LayoutParams(numProgressView2Size, numProgressView2Size));
125 | parent.addView(numProgressView2);
126 | ((LinearLayout.LayoutParams) numProgressView2.getLayoutParams()).leftMargin = 30;
127 | numProgressView2.setOnClickListener(new View.OnClickListener() {
128 | @Override
129 | public void onClick(View v) {
130 | numProgressView2.setCurProgress(0);
131 | numProgressView2.startFlickerArcProgress(mEndFlagRunnable);
132 | }
133 | });
134 | final GradientArcView gradientArcView = new GradientArcView(getBaseContext());
135 | gradientArcView.setLayoutParams(new ViewGroup.LayoutParams(numProgressView2Size, numProgressView2Size));
136 | parent.addView(gradientArcView);
137 | ((LinearLayout.LayoutParams) gradientArcView.getLayoutParams()).leftMargin = 30;
138 | gradientArcView.setOnClickListener(new View.OnClickListener() {
139 | @Override
140 | public void onClick(View v) {
141 | gradientArcView.startFlickerArcProgress(mEndFlagRunnable);
142 | }
143 | });
144 |
145 | final GradientArcProgressView gradientArcProgressView = new GradientArcProgressView(getBaseContext());
146 | gradientArcProgressView.setLayoutParams(new ViewGroup.LayoutParams(numProgressView2Size, numProgressView2Size));
147 | parent.addView(gradientArcProgressView);
148 | ((LinearLayout.LayoutParams) gradientArcProgressView.getLayoutParams()).leftMargin = 30;
149 | gradientArcProgressView.setOnClickListener(new View.OnClickListener() {
150 | @Override
151 | public void onClick(View v) {
152 | gradientArcProgressView.startFlickerArcProgress(mEndFlagRunnable);
153 | }
154 | });
155 |
156 | final GradientArcProgressView2 gradientArcProgressView2 = new GradientArcProgressView2(getBaseContext());
157 | gradientArcProgressView2.setLayoutParams(new ViewGroup.LayoutParams(numProgressView2Size, numProgressView2Size));
158 | parent.addView(gradientArcProgressView2);
159 | ((LinearLayout.LayoutParams) gradientArcProgressView2.getLayoutParams()).leftMargin = 30;
160 | gradientArcProgressView2.setOnClickListener(new View.OnClickListener() {
161 | @Override
162 | public void onClick(View v) {
163 | gradientArcProgressView2.startFlickerArcProgress(mEndFlagRunnable);
164 | }
165 | });
166 |
167 | final CircleProgressView circleProgressView = new CircleProgressView(getBaseContext());
168 | circleProgressView.setRoundProgressBgColor(0xff424045);
169 | circleProgressView.setRoundProgressBgColor(Color.WHITE);
170 | circleProgressView.setProgressColors(new int[] { 0x00535353, 0xff535353});
171 | circleProgressView.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
172 | parent.addView(circleProgressView);
173 | ((LinearLayout.LayoutParams) circleProgressView.getLayoutParams()).leftMargin = 30;
174 | }
175 |
176 | private void rotateOnXCoordinate() {
177 | float centerX = mRotateImgv.getWidth() / 2.0f;
178 | float centerY = mRotateImgv.getHeight() / 2.0f;
179 | float depthZ = 0f;
180 | Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(0, 180, centerX, centerY, depthZ, Rotate3dAnimation.ROTATE_X_AXIS, true);
181 | rotate3dAnimationX.setDuration(1000);
182 | mRotateImgv.startAnimation(rotate3dAnimationX);
183 |
184 | // 下面的代码,旋转的时候可以带透明度
185 | // float centerX = mRotateImgv.getWidth() / 2.0f;
186 | // float centerY = mRotateImgv.getHeight() / 2.0f;
187 | // float depthZ = 0f;
188 | // Rotate3dAnimationXY rotate3dAnimationX = new Rotate3dAnimationXY(0, 180, centerX, centerY, depthZ, true, (byte) 0);
189 | // rotate3dAnimationX.setDuration(1000);
190 | // mRotateImgv.startAnimation(rotate3dAnimationX);
191 | }
192 |
193 | private void rotateOnYCoordinate() {
194 | float centerX = mRotateImgv.getWidth() / 2.0f;
195 | float centerY = mRotateImgv.getHeight() / 2.0f;
196 | float centerZ = 0f;
197 |
198 | Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(0, 180, centerX, centerY, centerZ, Rotate3dAnimation.ROTATE_Y_AXIS, true);
199 | rotate3dAnimationX.setDuration(1000);
200 | mRotateImgv.startAnimation(rotate3dAnimationX);
201 | }
202 |
203 | private void rotateAnimHorizon() {
204 | float centerX = mRotateImgv.getWidth() / 2.0f;
205 | float centerY = mRotateImgv.getHeight() / 2.0f;
206 | float centerZ = 0f;
207 |
208 | Rotate3dAnimation rotate3dAnimationX = new Rotate3dAnimation(180, 0, centerX, centerY, centerZ, Rotate3dAnimation.ROTATE_Z_AXIS, true);
209 | rotate3dAnimationX.setDuration(1000);
210 | mRotateImgv.startAnimation(rotate3dAnimationX);
211 |
212 | // 下面是使用android自带的旋转动画
213 | // RotateAnimation rotateAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
214 | // rotateAnimation.setDuration(1000);
215 | // mRotateImgv.startAnimation(rotateAnimation);
216 | }
217 |
218 | @Override
219 | public boolean onCreateOptionsMenu(Menu menu) {
220 | // Inflate the menu; this adds items to the action bar if it is present.
221 | getMenuInflater().inflate(R.menu.menu_rotate, menu);
222 | return true;
223 | }
224 |
225 | @Override
226 | public boolean onOptionsItemSelected(MenuItem item) {
227 | // Handle action bar item clicks here. The action bar will
228 | // automatically handle clicks on the Home/Up button, so long
229 | // as you specify a parent activity in AndroidManifest.xml.
230 | int id = item.getItemId();
231 |
232 | //noinspection SimplifiableIfStatement
233 | if (id == R.id.action_settings) {
234 | return true;
235 | }
236 |
237 | return super.onOptionsItemSelected(item);
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/app/src/main/java/rotateanim/example/com/androidrotateanim/RoundNumProgressView.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.SweepGradient;
11 | import android.graphics.Typeface;
12 | import android.util.AttributeSet;
13 | import android.util.DisplayMetrics;
14 | import android.util.TypedValue;
15 | import android.view.View;
16 |
17 | import java.util.Iterator;
18 | import java.util.Vector;
19 |
20 | /**
21 | * Created by yuzhangsheng on 2015/11/17.
22 | * 带进度的圆弧进度条,线程安全的View,可直接在线程中更新进度
23 | * 可配置顺时针和逆时针旋转
24 | */
25 | public class RoundNumProgressView extends View {
26 |
27 | private static final int ROUND_COLOR_DEFAULT = 0x33ffffff;
28 | private static final int ROUND_WIDTH_DEFAULT = 2; //dp
29 | private static final int ROUND_PROGRESS_COLOR_DEFAULT = 0xffffffff;
30 | private static final int PERCENT_TEXTCOLOR_DEFAULT = 0xffffffff;
31 | private static final int PERCENT_TEXTSIZE_DEFAULT = 9; //sp
32 | private static final int MAX_PROGRESS_DEFAULT = 100;
33 | /** 允许显示的最大最小值 - 这个与mMaxProgress和 mMinProgress不一样 */
34 | private static final int ALLOW_SHOW_MAX = 95;
35 | private static final int ALLOW_SHOW_MIN = 5;
36 | private static final int PERCENT_BASE = 100;
37 |
38 | /** 正常累加进度每次移动的角度 */
39 | private static final int NORMAL_PROGRESS_STEP = 2;
40 | /** 闪烁进度条每次移动的角度 */
41 | private static final int FLICKER_PROGRESS_STEP = 40;
42 | private static final int TOTAL_DEGREE = 360;
43 | /** 闪烁进度的时候,画的弧长 */
44 | private static final int FLICKER_ARC_LENGTH = 270;
45 | /** 顶部作为计数起点, 右边是0,左边是-180或者180,底部是90 */
46 | private static final int START_POINT_TOP = -90;
47 |
48 | /** 定义一支画笔 */
49 | private Paint mPaint;
50 | private Paint mGradientArcPaint;
51 | private SweepGradient mSweepGradient;
52 | private int[] mColors = {
53 | 0x00ffffff, 0x40ffffff, 0x80ffffff, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, 0x80ffffff, 0x40ffffff, 0x00ffffff
54 | };
55 | private Matrix mMatrix = new Matrix();
56 | /** 圆环的颜色 */
57 | private int mRoundColor;
58 | /** 圆环的宽度 */
59 | private float mRoundWidth;
60 | /** 圆环进度的颜色 */
61 | private int mRoundProgressColor;
62 | /** 中间进度百分比的字符串的颜色 */
63 | private int mPercentTextColor;
64 | /** 中间进度百分比的字符串的字体 */
65 | private float mPercentTextSize;
66 | /** 最大进度数(可以允许超过100的,但是没什么意义,数字可以超过100%) */
67 | private int mMaxProgress;
68 | /** 允许显示的最大进度 */
69 | private int mAllowMaxProgress = ALLOW_SHOW_MAX;
70 | /** 允许显示的最小进度 */
71 | private int mAllowMinProgress = ALLOW_SHOW_MIN;
72 | /** 当前进度 */
73 | private int mCurProgress = ALLOW_SHOW_MIN;
74 |
75 | /** 是否显示中间的进度 */
76 | private boolean isPercentTextDisplayable = true;
77 | /** 用于定义的圆弧的形状和大小的界限 */
78 | private RectF mArcLimitRect = new RectF();
79 |
80 | /** 进度的风格,实心(FILL)或者空心(STROKE) */
81 | private int mStyle;
82 | public static final int STROKE = 0;
83 | public static final int FILL = 1;
84 |
85 | /** 进度旋转方向,顺时针(CLOCKWISE)或者逆时针(COUNTERCLOCKWISE) */
86 | private int mRotateOrientation;
87 | public static final int COUNTERCLOCKWISE = 0;
88 | public static final int CLOCKWISE = 1;
89 |
90 | /** 闪烁(循环旋转)进度条的时间 */
91 | private int mFlickerProgressTime = 1000;
92 | private int mFlickerProgressTotal = 0;
93 |
94 | /** 闪烁进度条动画正在进行 */
95 | private boolean isFlickerProgressWorking = false;
96 | private boolean isRefreshingProgress = false;
97 |
98 | private Vector mRoundNumProgressListeners;
99 |
100 | public interface IRoundNumProgressListener {
101 | void onFlickerProgressEnd();
102 | }
103 |
104 | public RoundNumProgressView(Context context) {
105 | this(context, null);
106 | }
107 |
108 | public RoundNumProgressView(Context context, AttributeSet attrs) {
109 | this(context, attrs, 0);
110 | }
111 |
112 | public RoundNumProgressView(Context context, AttributeSet attrs, int defStyle) {
113 | super(context, attrs, defStyle);
114 | mPaint = new Paint();
115 | mGradientArcPaint = new Paint();
116 | //获取自定义属性和默认值
117 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundNumProgressView);
118 | mRoundColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundColor, ROUND_COLOR_DEFAULT);
119 | mRoundProgressColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_roundProgressColor, ROUND_PROGRESS_COLOR_DEFAULT);
120 | mPercentTextColor = mTypedArray.getColor(R.styleable.RoundNumProgressView_percentTextColor, PERCENT_TEXTCOLOR_DEFAULT);
121 |
122 | final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
123 | final float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, PERCENT_TEXTSIZE_DEFAULT, metrics);
124 | final float roundWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ROUND_WIDTH_DEFAULT, metrics);
125 | mPercentTextSize = mTypedArray.getDimension(R.styleable.RoundNumProgressView_percentTextSize, textSize);
126 | mRoundWidth = mTypedArray.getDimension(R.styleable.RoundNumProgressView_roundWidth, roundWidth);
127 | mMaxProgress = mTypedArray.getInteger(R.styleable.RoundNumProgressView_maxProgress, MAX_PROGRESS_DEFAULT);
128 | isPercentTextDisplayable = mTypedArray.getBoolean(R.styleable.RoundNumProgressView_percentTextDisplayable, true);
129 | mStyle = mTypedArray.getInt(R.styleable.RoundNumProgressView_style, STROKE);
130 | mRotateOrientation = mTypedArray.getInt(R.styleable.RoundNumProgressView_rotateOrientation, COUNTERCLOCKWISE);
131 | mTypedArray.recycle();
132 | }
133 |
134 | public void addRoundNumProgressListener(IRoundNumProgressListener roundNumProgressListener) {
135 | if (roundNumProgressListener == null)
136 | return;
137 | if (mRoundNumProgressListeners == null) {
138 | mRoundNumProgressListeners = new Vector();
139 | }
140 | mRoundNumProgressListeners.add(roundNumProgressListener);
141 | }
142 |
143 | private void notifyAllRoundNumProressListeners() {
144 | if (mRoundNumProgressListeners == null)
145 | return;
146 | Iterator iterator = mRoundNumProgressListeners.iterator();
147 | while (iterator.hasNext()) {
148 | iterator.next().onFlickerProgressEnd();
149 | }
150 | }
151 |
152 | int centerX = 0; // 获取圆心的x坐标
153 | int radius = 0; // 圆环的半径
154 | @Override
155 | protected void onDraw(Canvas canvas) {
156 | super.onDraw(canvas);
157 | if (centerX == 0) {
158 | centerX = getWidth() / 2; // 获取圆心的x坐标
159 | }
160 | if (radius == 0) {
161 | radius = (int) (centerX - mRoundWidth / 2); // 圆环的半径
162 | }
163 | // 画最外层的大圆环
164 | drawOuterCircle(canvas, centerX, radius);
165 | // 画进度百分比
166 | drawPercentText(canvas, centerX);
167 | // 画闪烁的进度条动画
168 | if (isFlickerProgressWorking) {
169 | drawFlickerArcProgress(canvas, centerX, radius);
170 | } else {
171 | // 画圆弧 ,画圆环的进度
172 | drawArcProgress(canvas, centerX, radius);
173 | }
174 | }
175 |
176 | private void drawOuterCircle(final Canvas canvas, final int centerX, final int radius) {
177 | mPaint.setColor(mRoundColor); // 设置圆环的颜色
178 | mPaint.setStyle(Paint.Style.STROKE); // 设置空心
179 | mPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
180 | mPaint.setAntiAlias(true); // 消除锯齿
181 | canvas.drawCircle(centerX, centerX, radius, mPaint); // 画出圆环
182 | }
183 |
184 | private void drawPercentText(final Canvas canvas, final int center) {
185 | mPaint.setStrokeWidth(0);
186 | mPaint.setColor(mPercentTextColor);
187 | mPaint.setTextSize(mPercentTextSize);
188 | mPaint.setTypeface(Typeface.DEFAULT_BOLD); // 设置字体
189 | final int percent = (int) (((float) mCurProgress / (float) mMaxProgress) * PERCENT_BASE); // 中间的进度百分比,先转换成float在进行除法运算,不然都为0
190 | final float textWidth = mPaint.measureText(percent + "%"); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间
191 | if (isPercentTextDisplayable && percent != 0 && mStyle == STROKE) {
192 | canvas.drawText(percent + "%", center - textWidth / 2, center + mPercentTextSize / 2 - 3, mPaint); // 画出进度百分比
193 | }
194 | }
195 |
196 | private void drawArcProgress(final Canvas canvas, final int centerX, final int radius) {
197 | mPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
198 | mPaint.setColor(mRoundProgressColor); // 设置进度的颜色
199 | // 用于定义的圆弧的形状和大小的界限
200 | if (mArcLimitRect.isEmpty()) {
201 | mArcLimitRect.set(centerX - radius, centerX - radius, centerX + radius, centerX + radius);
202 | }
203 | if (mStyle == STROKE) {
204 | mPaint.setStyle(Paint.Style.STROKE);
205 | } else if (mStyle == FILL) {
206 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
207 | }
208 | final float percent = ((float) mCurProgress / (float) mMaxProgress);
209 | if (mRotateOrientation == COUNTERCLOCKWISE) { // 计数起点在顶部,所以为-90
210 | canvas.drawArc(mArcLimitRect, START_POINT_TOP, -TOTAL_DEGREE * percent, false, mPaint); // 根据进度画圆弧
211 | } else if (mRotateOrientation == CLOCKWISE) {
212 | canvas.drawArc(mArcLimitRect, START_POINT_TOP, TOTAL_DEGREE * percent, false, mPaint); // 根据进度画圆弧
213 | }
214 | }
215 |
216 | private void drawFlickerArcProgress(final Canvas canvas, final int centerX, final int radius) {
217 | mGradientArcPaint.setStrokeWidth(mRoundWidth); // 设置圆环的宽度
218 | mGradientArcPaint.setColor(mRoundProgressColor); // 设置进度的颜色
219 | mGradientArcPaint.setAntiAlias(true);
220 | if (mArcLimitRect.isEmpty()) {
221 | mArcLimitRect.set(centerX - radius, centerX - radius, centerX + radius, centerX + radius);
222 | }
223 | mGradientArcPaint.setStyle(Paint.Style.STROKE);
224 | // 定义一个梯度渲染,由于梯度渲染是从三点钟方向开始,所以再让他逆时针旋转90°,从0点开始
225 | if (mSweepGradient == null)
226 | mSweepGradient = new SweepGradient(centerX, centerX, mColors, null);
227 | mMatrix.setRotate(-90 - mFlickerProgressTotal, centerX, centerX);
228 | mSweepGradient.setLocalMatrix(mMatrix);
229 | mGradientArcPaint.setShader(mSweepGradient);
230 | canvas.drawCircle(centerX, centerX, radius, mGradientArcPaint); // 画出圆环
231 | post(new Runnable() {
232 | @Override
233 | public void run() {
234 | mFlickerProgressTotal += FLICKER_PROGRESS_STEP;
235 | postInvalidate();
236 | }
237 | });
238 | }
239 |
240 | /***
241 | * 启动闪烁动画,点击的时候调用会起到很好的提示作用
242 | */
243 | public void startFlickerArcProgress(final Runnable endFlagRunnable) {
244 | if (isFlickerProgressWorking)
245 | return;
246 | isFlickerProgressWorking = true;
247 | postInvalidate();
248 | postDelayed(new Runnable() {
249 | @Override
250 | public void run() {
251 | isFlickerProgressWorking = false;
252 | if (endFlagRunnable != null) {
253 | endFlagRunnable.run();
254 | }
255 | notifyAllRoundNumProressListeners();
256 | }
257 | }, mFlickerProgressTime);
258 | }
259 |
260 | private int mTempCurProgress;
261 | /**
262 | * 重新刷新显示进度,从0开始累加到要显示的值
263 | */
264 | public void reRefreshToOriginProgress() {
265 | reRefreshToOriginProgress(getCurProgress());
266 | }
267 |
268 | public void reRefreshToOriginProgress(final int toProgress) {
269 | if (isRefreshingProgress)
270 | return;
271 | if (toProgress <= mAllowMinProgress)
272 | return;
273 | mTempCurProgress = mAllowMinProgress;
274 | post(new Runnable() {
275 | @Override
276 | public void run() {
277 | if (mTempCurProgress >= toProgress) {
278 | isRefreshingProgress = false;
279 | setCurProgress(toProgress);
280 | return;
281 | }
282 | setCurProgress(mTempCurProgress += NORMAL_PROGRESS_STEP);
283 | post(this);
284 | }
285 | });
286 | }
287 |
288 | public boolean isFlickerProgressWorking() {
289 | return isFlickerProgressWorking;
290 | }
291 |
292 | public boolean isRefreshingProgress() {
293 | return isRefreshingProgress;
294 | }
295 |
296 | public synchronized int getMaxProgress() {
297 | return mMaxProgress;
298 | }
299 |
300 | public synchronized int getMinProgress() {
301 | return mMaxProgress;
302 | }
303 |
304 | /**
305 | * 设置总的进度数
306 | *
307 | * @param maxProgress
308 | */
309 | public synchronized void setMaxProgress(int maxProgress) {
310 | if (maxProgress < 0) {
311 | throw new IllegalArgumentException("max not less than 0");
312 | }
313 | mMaxProgress = maxProgress;
314 | }
315 |
316 | /**
317 | * 设置允许显示进度的最小值
318 | *
319 | * @param allowMinProgress
320 | */
321 | public synchronized void setAlloShowMinProgress(int allowMinProgress) {
322 | if (allowMinProgress < 0) {
323 | throw new IllegalArgumentException("min not less than 0");
324 | }
325 | mAllowMinProgress = allowMinProgress;
326 | }
327 |
328 | /**
329 | * 获取进度.需要同步
330 | *
331 | * @return
332 | */
333 | public synchronized int getCurProgress() {
334 | return mCurProgress;
335 | }
336 |
337 | /**
338 | * 设置进度,此为线程安全控件,由于考虑多线程的问题,需要同步
339 | * 刷新界面调用postInvalidate()能在非UI线程刷新
340 | *
341 | * @param curProgress
342 | */
343 | public synchronized void setCurProgress(int curProgress) {
344 | if (curProgress < 0) {
345 | throw new IllegalArgumentException("progress not less than 0");
346 | }
347 | if (curProgress > mAllowMaxProgress) {
348 | curProgress = mAllowMaxProgress;
349 | } else if (curProgress < mAllowMinProgress) {
350 | curProgress = mAllowMinProgress;
351 | }
352 | mCurProgress = curProgress;
353 | postInvalidate();
354 | }
355 |
356 | public int getOuterRoundColor() {
357 | return mRoundColor;
358 | }
359 |
360 | public void setOuterRoundColor(int roundColor) {
361 | mRoundColor = roundColor;
362 | }
363 |
364 | public int getRoundProgressColor() {
365 | return mRoundProgressColor;
366 | }
367 |
368 | public void setRoundProgressColor(int roundProgressColor) {
369 | mRoundProgressColor = roundProgressColor;
370 | }
371 |
372 | public int getPercentTextColor() {
373 | return mPercentTextColor;
374 | }
375 |
376 | public void setPercentTextColor(int textColor) {
377 | mPercentTextColor = textColor;
378 | }
379 |
380 | public float getPercentTextSize() {
381 | return mPercentTextSize;
382 | }
383 |
384 | public void setPercentTextSize(float percentTextSize) {
385 | mPercentTextSize = percentTextSize;
386 | }
387 |
388 | public float getRoundWidth() {
389 | return mRoundWidth;
390 | }
391 |
392 | public void setRoundWidth(float roundWidth) {
393 | mRoundWidth = roundWidth;
394 | }
395 |
396 | public void setRotateOrientation(int rotateOrientation) {
397 | mRotateOrientation = rotateOrientation;
398 | }
399 |
400 | public void setStyle(int style) {
401 | mStyle = style;
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/test1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/drawable/test1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/test2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/drawable/test2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/test3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/drawable/test3.jpg
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
22 |
23 |
28 |
29 |
34 |
35 |
43 |
44 |
52 |
65 |
66 |
67 |
75 |
76 |
81 |
82 |
87 |
88 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_rotate.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidRotateAnim
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/test/java/rotateanim/example/com/androidrotateanim/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package rotateanim.example.com.androidrotateanim;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.2'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/docpic/RotateAnim.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/docpic/RotateAnim.gif
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PopFisher/AndroidRotateAnim/93876bb6bc779113ed1bf9685df631671342d2a3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Nov 04 20:49:52 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------