Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 65ca371

Browse files
author
dinuscxj
committed
add the CollisionLoadingRenderer
1 parent bf31801 commit 65ca371

File tree

6 files changed

+235
-12
lines changed

6 files changed

+235
-12
lines changed

Preview/CircleLoadingDrawable.gif

358 KB
Loading

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
ImageView.setImageDrawable(new LoadingDrawable(new WhorlLoadingRenderer(Context)));
2626
ImageView.setImageDrawable(new LoadingDrawable(new LevelLoadingRenderer(Context)));
2727
ImageView.setImageDrawable(new LoadingDrawable(new MaterialLoadingRenderer(Context)));
28+
ImageView.setImageDrawable(new LoadingDrawable(new CollisionLoadingRenderer(Context)));
2829
```
2930

3031
Used with View
@@ -33,6 +34,7 @@
3334
View.setBackground(new LoadingDrawable(new WhorlLoadingRenderer(Context)));
3435
View.setBackground(new LoadingDrawable(new LevelLoadingRenderer(Context)));
3536
View.setBackground(new LoadingDrawable(new MaterialLoadingRenderer(Context)));
37+
View.setBackground(new LoadingDrawable(new CollisionLoadingRenderer(Context)));
3638
```
3739

3840
## License

app/src/main/java/app/dinus/com/example/MainActivity.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import android.os.Bundle;
44
import android.support.v7.app.AppCompatActivity;
5-
import android.view.View;
65
import android.widget.ImageView;
76

7+
import app.dinus.com.loadingdrawable.CollisionLoadingRenderer;
88
import app.dinus.com.loadingdrawable.GearLoadingRenderer;
99
import app.dinus.com.loadingdrawable.LevelLoadingRenderer;
1010
import app.dinus.com.loadingdrawable.LoadingDrawable;
11-
import app.dinus.com.loadingdrawable.LoadingRenderer;
1211
import app.dinus.com.loadingdrawable.MaterialLoadingRenderer;
1312
import app.dinus.com.loadingdrawable.WhorlLoadingRenderer;
1413

@@ -18,11 +17,13 @@ public class MainActivity extends AppCompatActivity {
1817
private LoadingDrawable mWhorlDrawable;
1918
private LoadingDrawable mLevelDrawable;
2019
private LoadingDrawable mMaterialDrawable;
20+
private LoadingDrawable mCollisionDrawable;
2121

2222
private ImageView mIvGear;
2323
private ImageView mIvWhorl;
2424
private ImageView mIvLevel;
2525
private ImageView mIvMaterial;
26+
private ImageView mIvCollision;
2627

2728
@Override
2829
protected void onCreate(Bundle savedInstanceState) {
@@ -33,16 +34,19 @@ protected void onCreate(Bundle savedInstanceState) {
3334
mIvWhorl = (ImageView) findViewById(R.id.whorl_view);
3435
mIvLevel = (ImageView) findViewById(R.id.level_view);
3536
mIvMaterial = (ImageView) findViewById(R.id.material_view);
37+
mIvCollision = (ImageView) findViewById(R.id.collision_view);
3638

3739
mGearDrawable = new LoadingDrawable(new GearLoadingRenderer(this));
3840
mWhorlDrawable = new LoadingDrawable(new WhorlLoadingRenderer(this));
3941
mLevelDrawable = new LoadingDrawable(new LevelLoadingRenderer(this));
4042
mMaterialDrawable = new LoadingDrawable(new MaterialLoadingRenderer(this));
43+
mCollisionDrawable = new LoadingDrawable(new CollisionLoadingRenderer(this));
4144

4245
mIvGear.setImageDrawable(mGearDrawable);
4346
mIvWhorl.setImageDrawable(mWhorlDrawable);
4447
mIvLevel.setImageDrawable(mLevelDrawable);
4548
mIvMaterial.setImageDrawable(mMaterialDrawable);
49+
mIvCollision.setImageDrawable(mCollisionDrawable);
4650
}
4751

4852
@Override
@@ -52,6 +56,7 @@ protected void onStart() {
5256
mWhorlDrawable.start();
5357
mLevelDrawable.start();
5458
mMaterialDrawable.start();
59+
mCollisionDrawable.start();
5560
}
5661

5762
@Override
@@ -60,6 +65,7 @@ protected void onStop() {
6065
mWhorlDrawable.stop();
6166
mLevelDrawable.stop();
6267
mMaterialDrawable.stop();
68+
mCollisionDrawable.stop();
6369
super.onStop();
6470
}
6571
}

app/src/main/res/layout/activity_main.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,28 @@
4545
android:background="#fff1c02e"
4646
android:layout_height="match_parent" />
4747
</LinearLayout>
48+
49+
<LinearLayout
50+
android:layout_weight="1"
51+
android:orientation="horizontal"
52+
android:layout_width="match_parent"
53+
android:layout_height="0dp">
54+
55+
<ImageView
56+
android:id="@+id/collision_view"
57+
android:layout_weight="1"
58+
android:layout_width="0dp"
59+
android:background="#ffe9e4d1"
60+
android:layout_height="match_parent" />
61+
62+
<TextView
63+
android:id="@+id/rotate_view"
64+
android:layout_weight="1"
65+
android:gravity="center"
66+
android:layout_width="0dp"
67+
android:textColor="#ffa10008"
68+
android:textSize="20sp"
69+
android:text="waiting ..."
70+
android:layout_height="match_parent" />
71+
</LinearLayout>
4872
</LinearLayout>
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package app.dinus.com.loadingdrawable;
2+
3+
import android.content.Context;
4+
import android.graphics.Canvas;
5+
import android.graphics.Color;
6+
import android.graphics.ColorFilter;
7+
import android.graphics.LinearGradient;
8+
import android.graphics.Paint;
9+
import android.graphics.Rect;
10+
import android.graphics.RectF;
11+
import android.graphics.Shader;
12+
import android.support.annotation.NonNull;
13+
import android.util.DisplayMetrics;
14+
import android.util.TypedValue;
15+
import android.view.animation.AccelerateInterpolator;
16+
import android.view.animation.DecelerateInterpolator;
17+
import android.view.animation.Interpolator;
18+
19+
public class CollisionLoadingRenderer extends LoadingRenderer {
20+
private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
21+
private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
22+
23+
private static final float DEFAULT_WIDTH = 15.0f * 11;
24+
private static final float DEFAULT_HEIGHT = 15.0f * 5;
25+
26+
private static final float DURATION_OFFSET = 0.25f;
27+
private static final float START_LEFT_DURATION_OFFSET = 0.25f;
28+
private static final float START_RIGHT_DURATION_OFFSET = 0.5f;
29+
private static final float END_RIGHT_DURATION_OFFSET = 0.75f;
30+
31+
private static final int CIRCLE_COUNT = 7;
32+
33+
private static final int[] DEFAULT_COLORS = new int[] {
34+
Color.RED, Color.GREEN
35+
};
36+
37+
private static final float[] DEFAULT_POSITIONS = new float[] {
38+
0.0f, 1.0f
39+
};
40+
41+
private final Paint mPaint = new Paint();
42+
private final RectF mTempBounds = new RectF();
43+
44+
private int[] mColors;
45+
private float[] mPositions;
46+
47+
private float mEndXOffsetProgress;
48+
private float mStartXOffsetProgress;
49+
50+
public CollisionLoadingRenderer(Context context) {
51+
super(context);
52+
setupPaint();
53+
54+
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
55+
mWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_WIDTH, displayMetrics);
56+
mHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_HEIGHT, displayMetrics);
57+
}
58+
59+
private void setupPaint() {
60+
mColors = DEFAULT_COLORS;
61+
mPositions = DEFAULT_POSITIONS;
62+
63+
mPaint.setAntiAlias(true);
64+
mPaint.setStrokeWidth(getStrokeWidth());
65+
mPaint.setStyle(Paint.Style.FILL);
66+
}
67+
68+
@Override
69+
public void draw(Canvas canvas, Rect bounds) {
70+
int saveCount = canvas.save();
71+
72+
RectF arcBounds = mTempBounds;
73+
arcBounds.set(bounds);
74+
75+
LinearGradient gradient = new LinearGradient(arcBounds.left, 0, arcBounds.right, 0,
76+
mColors, mPositions, Shader.TileMode.CLAMP);
77+
mPaint.setShader(gradient);
78+
79+
float cy = mHeight / 2 ;
80+
float circleRadius = computeCircleRadius(arcBounds);
81+
82+
float sideOffset = 2.0f * (2 * circleRadius);
83+
float maxMoveOffset = 1.5f * (2 * circleRadius);
84+
85+
for (int i = 0; i < CIRCLE_COUNT; i++) {
86+
if (i == 0 && mStartXOffsetProgress != 0) {
87+
float xMoveOffset = maxMoveOffset * mStartXOffsetProgress;
88+
// y = ax^2 --> if x = sideOffset, y = sideOffset ==> a = 1 / sideOffset
89+
float yMoveOffset = (float) (Math.pow(xMoveOffset, 2) / maxMoveOffset);
90+
canvas.drawCircle(circleRadius + sideOffset - xMoveOffset , cy - yMoveOffset, circleRadius, mPaint);
91+
continue;
92+
}
93+
94+
if (i == CIRCLE_COUNT - 1 && mEndXOffsetProgress != 0) {
95+
float xMoveOffset = maxMoveOffset * mEndXOffsetProgress;
96+
// y = ax^2 --> if x = sideOffset, y = sideOffset / 2 ==> a = 1 / sideOffset
97+
float yMoveOffset = (float) (Math.pow(xMoveOffset, 2) / maxMoveOffset);
98+
canvas.drawCircle(circleRadius * (CIRCLE_COUNT * 2 - 1) + sideOffset + xMoveOffset , cy - yMoveOffset, circleRadius, mPaint);
99+
continue;
100+
}
101+
102+
canvas.drawCircle(circleRadius * (i * 2 + 1) + sideOffset , cy, circleRadius, mPaint);
103+
}
104+
105+
canvas.restoreToCount(saveCount);
106+
}
107+
108+
private float computeCircleRadius(RectF rectBounds) {
109+
float width = rectBounds.width();
110+
float height = rectBounds.height();
111+
112+
//CIRCLE_COUNT + 4 is the sliding distance of both sides
113+
float radius = Math.min(width / (CIRCLE_COUNT + 4) / 2, height / 2);
114+
return radius;
115+
}
116+
117+
@Override
118+
public void computeRender(float renderProgress) {
119+
120+
// Moving the start offset to left only occurs in the first 25% of a
121+
// single ring animation
122+
if (renderProgress <= START_LEFT_DURATION_OFFSET) {
123+
float startLeftOffsetProgress = renderProgress / DURATION_OFFSET;
124+
mStartXOffsetProgress = DECELERATE_INTERPOLATOR.getInterpolation(startLeftOffsetProgress);
125+
126+
invalidateSelf();
127+
return ;
128+
}
129+
130+
// Moving the start offset to left only occurs between 25% and 50% of a
131+
// single ring animation
132+
if (renderProgress <= START_RIGHT_DURATION_OFFSET) {
133+
float startRightOffsetProgress = (renderProgress - START_LEFT_DURATION_OFFSET) / DURATION_OFFSET;
134+
mStartXOffsetProgress = ACCELERATE_INTERPOLATOR.getInterpolation(1.0f - startRightOffsetProgress);
135+
136+
invalidateSelf();
137+
return ;
138+
}
139+
140+
// Moving the end offset to right starts between 50% and 75% a single ring
141+
// animation completes
142+
if (renderProgress <= END_RIGHT_DURATION_OFFSET) {
143+
float endRightOffsetProgress = (renderProgress - START_RIGHT_DURATION_OFFSET) / DURATION_OFFSET;
144+
mEndXOffsetProgress = DECELERATE_INTERPOLATOR.getInterpolation(endRightOffsetProgress);
145+
146+
invalidateSelf();
147+
return ;
148+
}
149+
150+
// Moving the end offset to left starts after 75% of a single ring
151+
// animation completes
152+
if (renderProgress <= 1.0f) {
153+
float endRightOffsetProgress = (renderProgress - END_RIGHT_DURATION_OFFSET) / DURATION_OFFSET;
154+
mEndXOffsetProgress = ACCELERATE_INTERPOLATOR.getInterpolation(1 - endRightOffsetProgress);
155+
156+
invalidateSelf();
157+
return ;
158+
}
159+
}
160+
161+
@Override
162+
public void setAlpha(int alpha) {
163+
mPaint.setAlpha(alpha);
164+
invalidateSelf();
165+
}
166+
167+
@Override
168+
public void setColorFilter(ColorFilter cf) {
169+
mPaint.setColorFilter(cf);
170+
invalidateSelf();
171+
}
172+
173+
@Override
174+
public void reset() {
175+
}
176+
177+
public void setColors(@NonNull int[] colors) {
178+
mColors = colors;
179+
}
180+
181+
public void setPositions(@NonNull float[] positions) {
182+
mPositions = positions;
183+
}
184+
185+
@Override
186+
public void setStrokeWidth(float strokeWidth) {
187+
super.setStrokeWidth(strokeWidth);
188+
mPaint.setStrokeWidth(strokeWidth);
189+
invalidateSelf();
190+
}
191+
}

library/src/main/java/app/dinus/com/loadingdrawable/LoadingRenderer.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
import android.view.animation.LinearInterpolator;
1414

1515
public abstract class LoadingRenderer {
16+
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
17+
1618
private static final int ANIMATION_DURATION = 1333;
1719

18-
private static final int DEFAULT_CIRCLE_DIAMETER = 56;
20+
private static final float DEFAULT_SIZE = 56.0f;
1921
private static final float DEFAULT_CENTER_RADIUS = 12.5f;
2022
private static final float DEFAULT_STROKE_WIDTH = 2.5f;
2123

22-
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
23-
24-
private float mWidth;
25-
private float mHeight;
26-
private float mStrokeWidth;
27-
private float mCenterRadius;
24+
protected float mWidth;
25+
protected float mHeight;
26+
protected float mStrokeWidth;
27+
protected float mCenterRadius;
2828

2929
private Drawable.Callback mCallback;
3030
private ValueAnimator mRenderAnimator;
@@ -41,7 +41,7 @@ public LoadingRenderer(Context context) {
4141
public abstract void reset();
4242

4343
public void start() {
44-
mRenderAnimator.setDuration(ANIMATION_DURATION * 10);
44+
mRenderAnimator.setDuration(ANIMATION_DURATION);
4545
mRenderAnimator.start();
4646
}
4747

@@ -66,8 +66,8 @@ private void setupDefaultParams(Context context) {
6666
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
6767
final float screenDensity = metrics.density;
6868

69-
mWidth = DEFAULT_CIRCLE_DIAMETER * screenDensity;
70-
mHeight = DEFAULT_CIRCLE_DIAMETER * screenDensity;
69+
mWidth = DEFAULT_SIZE * screenDensity;
70+
mHeight = DEFAULT_SIZE * screenDensity;
7171
mStrokeWidth = DEFAULT_STROKE_WIDTH * screenDensity;
7272
mCenterRadius = DEFAULT_CENTER_RADIUS * screenDensity;
7373
}

0 commit comments

Comments
 (0)