@@ -2,6 +2,7 @@ package com.smarttoolfactory.progressindicator
22
33import androidx.compose.animation.core.*
44import androidx.compose.foundation.Canvas
5+ import androidx.compose.foundation.border
56import androidx.compose.foundation.layout.size
67import androidx.compose.runtime.Composable
78import androidx.compose.runtime.getValue
@@ -19,87 +20,111 @@ enum class SpinnerShape {
1920 Rect , RoundedRect
2021}
2122
23+ /* *
24+ * Indeterminate Material Design spinning progress indicator with rectangle or rounded rectangle
25+ * shape.
26+ * @param staticItemColor color of the spinning items
27+ * @param dynamicItemColor color of the stationary items
28+ * @param spinnerShape shape of the items whether [SpinnerShape.Rect] or [SpinnerShape.RoundedRect]
29+ * @param durationMillis duration of one cycle of spinning
30+ */
2231@Composable
2332fun SpinningProgressIndicator (
2433 modifier : Modifier = Modifier ,
2534 staticItemColor : Color = StaticItemColor ,
2635 dynamicItemColor : Color = DynamicItemColor ,
2736 spinnerShape : SpinnerShape = SpinnerShape .RoundedRect ,
28- durationInMillis : Int = 1000
37+ durationMillis : Int = 1000
2938) {
3039
3140 val count = 12
41+ val coefficient = 360f / count
3242
3343 val infiniteTransition = rememberInfiniteTransition()
3444 val angle by infiniteTransition.animateFloat(
3545 initialValue = 0f ,
3646 targetValue = count.toFloat(),
3747 animationSpec = infiniteRepeatable(
38- animation = tween(durationInMillis, easing = LinearEasing ),
48+ animation = tween(
49+ durationMillis = durationMillis,
50+ easing = LinearEasing
51+ ),
3952 repeatMode = RepeatMode .Restart
4053 )
4154 )
4255
56+ Canvas (
57+ modifier = modifier
58+ .size(48 .dp)
59+ .border(1 .dp, Color .Red )
60+ ) {
4361
44- Canvas (modifier = modifier.size(48 .dp)) {
62+ var canvasWidth = size.width
63+ var canvasHeight = size.height
4564
46- val canvasWidth = size.width
47- val canvasHeight = size.height
65+ if (canvasHeight < canvasWidth) {
66+ canvasWidth = canvasHeight
67+ } else {
68+ canvasHeight = canvasWidth
69+ }
70+
71+ val itemWidth = canvasWidth * .3f
72+ val itemHeight = canvasHeight / 12
73+
74+ val cornerRadius = itemWidth.coerceAtMost(itemHeight) / 2
75+
76+ val horizontalOffset = (size.width - size.height).coerceAtLeast(0f ) / 2
77+ val verticalOffset = (size.height - size.width).coerceAtLeast(0f ) / 2
4878
49- val width = canvasWidth * .3f
50- val height = canvasHeight / 12
79+ val topLeftOffset = Offset (
80+ x = horizontalOffset + canvasWidth - itemWidth,
81+ y = verticalOffset + (canvasHeight - itemHeight) / 2
82+ )
5183
52- val cornerRadius = width.coerceAtMost(height) / 2
84+ val size = Size (itemWidth, itemHeight)
5385
5486 // Stationary items
5587 for (i in 0 .. 360 step 360 / count) {
5688 rotate(i.toFloat()) {
5789 if (spinnerShape == SpinnerShape .RoundedRect ) {
5890 drawRoundRect(
5991 color = staticItemColor,
60- topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ) ,
61- size = Size (width, height) ,
92+ topLeft = topLeftOffset ,
93+ size = size ,
6294 cornerRadius = CornerRadius (cornerRadius, cornerRadius)
6395 )
6496 } else {
6597 drawRect(
6698 color = staticItemColor,
67- topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ) ,
68- size = Size (width, height)
99+ topLeft = topLeftOffset ,
100+ size = size,
69101 )
70102 }
71103 }
72104 }
73105
74- val coefficient = 360f / count
75-
76- // Dynamic items
77- for (i in 0 .. count / 2 ) {
78- rotate((angle.toInt() + i) * coefficient) {
79- if (spinnerShape == SpinnerShape .RoundedRect ) {
80- drawRoundRect(
81- color = dynamicItemColor.copy(
82- alpha = (0.2f + 0.15f * i).coerceIn(
83- 0f , 1f
84- )
85- ),
86- topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ),
87- size = Size (width, height),
88- cornerRadius = CornerRadius (cornerRadius, cornerRadius)
89- )
90- } else {
91- drawRect(
92- color = dynamicItemColor.copy(
93- alpha = (0.2f + 0.15f * i).coerceIn(
94- 0f , 1f
95- )
96- ),
97- topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ),
98- size = Size (width, height)
99- )
100- }
106+ // Dynamic items
107+ for (i in 0 .. count / 2 ) {
108+ rotate((angle.toInt() + i) * coefficient) {
109+ if (spinnerShape == SpinnerShape .RoundedRect ) {
110+ drawRoundRect(
111+ color = dynamicItemColor.copy(alpha = (0.2f + 0.15f * i).coerceIn(0f , 1f )),
112+ topLeft = topLeftOffset,
113+ size = size,
114+ cornerRadius = CornerRadius (cornerRadius, cornerRadius)
115+ )
116+ } else {
117+ drawRect(
118+ color = dynamicItemColor.copy(
119+ alpha = (0.2f + 0.15f * i).coerceIn(
120+ 0f , 1f
121+ )
122+ ),
123+ topLeft = topLeftOffset,
124+ size = size,
125+ )
101126 }
102127 }
128+ }
103129 }
104130}
105-
0 commit comments