@@ -12,41 +12,64 @@ import androidx.compose.ui.geometry.Offset
1212import androidx.compose.ui.graphics.Color
1313import androidx.compose.ui.graphics.drawscope.rotate
1414import androidx.compose.ui.unit.dp
15- import com.smarttoolfactory.progressindicator.ui.theme.DynamicItemColor
16- import com.smarttoolfactory.progressindicator.ui.theme.StaticItemColor
17-
18-
15+ import com.smarttoolfactory.progressindicator.IndicatorDefaults.DynamicItemColor
16+ import com.smarttoolfactory.progressindicator.IndicatorDefaults.StaticItemColor
17+
18+ /* *
19+ * Indeterminate Material Design spinning progress indicator with circle items
20+ * shape.
21+ * @param staticItemColor color of the spinning items
22+ * @param dynamicItemColor color of the stationary items
23+ * @param durationMillis duration of one cycle of spinning
24+ */
1925@Composable
2026fun SpinningCircleProgressIndicator (
2127 modifier : Modifier = Modifier ,
2228 staticItemColor : Color = StaticItemColor ,
2329 dynamicItemColor : Color = DynamicItemColor ,
24- durationInMillis : Int = 1000
30+ durationMillis : Int = 1000
2531) {
2632 val count = 8
2733
2834 val infiniteTransition = rememberInfiniteTransition()
2935 val angle by infiniteTransition.animateFloat(
30- initialValue = 0f , targetValue = count.toFloat(), animationSpec = infiniteRepeatable(
31- animation = tween(durationInMillis, easing = LinearEasing ),
36+ initialValue = 0f , targetValue = count.toFloat(),
37+ animationSpec = infiniteRepeatable(
38+ animation = tween(
39+ durationMillis = durationMillis,
40+ easing = LinearEasing
41+ ),
3242 repeatMode = RepeatMode .Restart
3343 )
3444 )
3545
36- Canvas (modifier = modifier.size(48 .dp )) {
46+ Canvas (modifier = modifier.size(Size )) {
3747
38- val canvasWidth = size.width
39- val canvasHeight = size.height
48+ var canvasWidth = size.width
49+ var canvasHeight = size.height
50+
51+ if (canvasHeight < canvasWidth) {
52+ canvasWidth = canvasHeight
53+ } else {
54+ canvasHeight = canvasWidth
55+ }
4056
4157 val radius = canvasWidth * .12f
4258
59+ val horizontalOffset = (size.width - size.height).coerceAtLeast(0f ) / 2
60+ val verticalOffset = (size.height - size.width).coerceAtLeast(0f ) / 2
61+ val center = Offset (
62+ x = horizontalOffset + canvasWidth - radius,
63+ y = verticalOffset + canvasHeight / 2
64+ )
65+
4366 // Stationary items
4467 for (i in 0 .. 360 step 360 / count) {
4568 rotate(i.toFloat()) {
4669 drawCircle(
4770 color = staticItemColor,
4871 radius = radius,
49- center = Offset (canvasWidth - radius, canvasHeight / 2 ) ,
72+ center = center ,
5073 )
5174 }
5275 }
@@ -63,17 +86,26 @@ fun SpinningCircleProgressIndicator(
6386 )
6487 ),
6588 radius = radius,
66- center = Offset (canvasWidth - radius, canvasHeight / 2 ) ,
89+ center = center ,
6790 )
6891 }
6992 }
7093 }
7194}
7295
96+ /* *
97+ * Indeterminate Material Design spinning progress indicator with circle items that are
98+ * with each item smaller than next
99+ * shape.
100+ * @param staticItemColor color of the spinning items
101+ * @param color color of the items
102+ * @param durationMillis duration of one cycle of spinning
103+ */
73104@Composable
74105fun ScaledCircleProgressIndicator (
75106 modifier : Modifier = Modifier ,
76- color : Color = MaterialTheme .colorScheme.primary
107+ color : Color = MaterialTheme .colorScheme.primary,
108+ durationMillis : Int = 1200
77109) {
78110 val count = 8f
79111
@@ -83,10 +115,10 @@ fun ScaledCircleProgressIndicator(
83115 targetValue = count,
84116 infiniteRepeatable(
85117 animation = keyframes {
86- durationMillis = 1100
87- count * 0.8f at 700
88- count * 0.1f at 150 with FastOutLinearInEasing
89- count * 0.10f at 150
118+ this . durationMillis = durationMillis
119+ count * 0.9f at (durationMillis * 0.8f ).toInt()
120+ count * 0.05f at (durationMillis * 0.1f ).toInt() with FastOutLinearInEasing
121+ count * 0.05f at (durationMillis * 0.1f ).toInt()
90122 }
91123 )
92124 )
@@ -95,8 +127,14 @@ fun ScaledCircleProgressIndicator(
95127
96128 Canvas (modifier = modifier.size(48 .dp)) {
97129
98- val canvasWidth = size.width
99- val canvasHeight = size.height
130+ var canvasWidth = size.width
131+ var canvasHeight = size.height
132+
133+ if (canvasHeight < canvasWidth) {
134+ canvasWidth = canvasHeight
135+ } else {
136+ canvasHeight = canvasWidth
137+ }
100138
101139 val coefficient = 360f / count
102140
@@ -114,6 +152,10 @@ fun ScaledCircleProgressIndicator(
114152
115153 val radiusDynamicContainer = (canvasWidth - radiusList.last())
116154
155+ val horizontalOffset = (size.width - size.height).coerceAtLeast(0f ) / 2
156+ val verticalOffset = (size.height - size.width).coerceAtLeast(0f ) / 2
157+ val center =
158+ Offset (horizontalOffset + radiusDynamicContainer, verticalOffset + canvasHeight / 2 )
117159
118160 // Dynamic items
119161 for (i in 0 until radiusList.size) {
@@ -122,11 +164,13 @@ fun ScaledCircleProgressIndicator(
122164
123165 rotate((angle + i) * coefficient) {
124166 drawCircle(
125- color = color.copy(alpha = ( i * .2f ).coerceIn(0f , 1f )),
167+ color = color.copy(alpha = (i * .2f ).coerceIn(0f , 1f )),
126168 radius = radius,
127- center = Offset (radiusDynamicContainer, canvasHeight / 2 ) ,
169+ center = center ,
128170 )
129171 }
130172 }
131173 }
132- }
174+ }
175+
176+ internal val Size = 48.0 .dp
0 commit comments