11package com.smarttoolfactory.progressindicator
22
3- import androidx.compose.animation.*
43import androidx.compose.animation.core.*
54import androidx.compose.foundation.Canvas
6- import androidx.compose.foundation.border
75import androidx.compose.foundation.layout.size
86import androidx.compose.runtime.Composable
97import androidx.compose.runtime.getValue
10- import androidx.compose.runtime.remember
118import androidx.compose.ui.Modifier
129import androidx.compose.ui.geometry.CornerRadius
1310import androidx.compose.ui.geometry.Offset
1411import androidx.compose.ui.geometry.Size
1512import androidx.compose.ui.graphics.Color
1613import androidx.compose.ui.graphics.drawscope.rotate
1714import androidx.compose.ui.unit.dp
15+ import com.smarttoolfactory.progressindicator.ui.theme.DynamicItemColor
16+ import com.smarttoolfactory.progressindicator.ui.theme.StaticItemColor
17+
18+ enum class SpinnerShape {
19+ Rect , RoundedRect
20+ }
1821
19- @OptIn(ExperimentalAnimationApi ::class )
2022@Composable
2123fun SpinningProgressIndicator (
2224 modifier : Modifier = Modifier ,
23- show : Boolean = true
25+ staticItemColor : Color = StaticItemColor ,
26+ dynamicItemColor : Color = DynamicItemColor ,
27+ spinnerShape : SpinnerShape = SpinnerShape .RoundedRect ,
28+ durationInMillis : Int = 1000
2429) {
2530
2631 val count = 12
@@ -30,188 +35,71 @@ fun SpinningProgressIndicator(
3035 initialValue = 0f ,
3136 targetValue = count.toFloat(),
3237 animationSpec = infiniteRepeatable(
33- animation = tween(count * 60 , easing = LinearEasing ),
38+ animation = tween(durationInMillis , easing = LinearEasing ),
3439 repeatMode = RepeatMode .Restart
3540 )
3641 )
3742
38- val backgroundColor = Color .Gray
39- // val foregroundColor = Color(0xff9E9E9E)
40- val foregroundColor = Color (0xffCDCDCD )
4143
42- AnimatedVisibility (
43- visible = show,
44- enter = scaleIn() + fadeIn(),
45- exit = scaleOut() + fadeOut()
46- ) {
47- Canvas (modifier = modifier.size(48 .dp)) {
44+ Canvas (modifier = modifier.size(48 .dp)) {
4845
49- val canvasWidth = size.width
50- val canvasHeight = size.height
46+ val canvasWidth = size.width
47+ val canvasHeight = size.height
5148
52- val width = canvasWidth * .3f
53- val height = canvasHeight / 10
49+ val width = canvasWidth * .3f
50+ val height = canvasHeight / 12
5451
55- val cornerRadius = width.coerceAtMost(height) / 2
52+ val cornerRadius = width.coerceAtMost(height) / 2
5653
57- // Stationary items
58- for (i in 0 .. 360 step 360 / count) {
59- rotate(i.toFloat()) {
54+ // Stationary items
55+ for (i in 0 .. 360 step 360 / count) {
56+ rotate(i.toFloat()) {
57+ if (spinnerShape == SpinnerShape .RoundedRect ) {
6058 drawRoundRect(
61- color = backgroundColor ,
59+ color = staticItemColor ,
6260 topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ),
6361 size = Size (width, height),
6462 cornerRadius = CornerRadius (cornerRadius, cornerRadius)
6563 )
66- }
67- }
68-
69- val coefficient = 360f / count
70-
71- // Dynamic items
72- for (i in 0 .. count / 2 ) {
73- rotate((angle.toInt() + i) * coefficient) {
74- drawRoundRect(
75- color = foregroundColor.copy(alpha = (0.2f + 0.15f * i).coerceIn(0f , 1f )),
64+ } else {
65+ drawRect(
66+ color = staticItemColor,
7667 topLeft = Offset (canvasWidth - width, (canvasHeight - height) / 2 ),
77- size = Size (width, height),
78- cornerRadius = CornerRadius (cornerRadius, cornerRadius)
68+ size = Size (width, height)
7969 )
8070 }
8171 }
8272 }
83- }
84- }
85-
86- @OptIn(ExperimentalAnimationApi ::class )
87- @Composable
88- fun SpinningCircleProgressIndicator (
89- modifier : Modifier = Modifier ,
90- show : Boolean = true
91- ) {
92-
93- val count = 8
94-
95- val infiniteTransition = rememberInfiniteTransition()
96- val angle by infiniteTransition.animateFloat(
97- initialValue = 0f ,
98- targetValue = count.toFloat(),
99- animationSpec = infiniteRepeatable(
100- animation = tween(count * 120 , easing = LinearEasing ),
101- repeatMode = RepeatMode .Restart
102- )
103- )
104-
105- val backgroundColor = Color .DarkGray
106- val foregroundColor = Color (0xff9E9E9E )
107-
108- AnimatedVisibility (
109- visible = show,
110- enter = scaleIn() + fadeIn(),
111- exit = scaleOut() + fadeOut()
112- ) {
113- Canvas (modifier = modifier.size(48 .dp)) {
114-
115- val canvasWidth = size.width
116- val canvasHeight = size.height
117-
118- val radius = canvasWidth * .1f
119-
120- // Stationary items
121- for (i in 0 .. 360 step 360 / count) {
122- rotate(i.toFloat()) {
123- drawCircle(
124- color = backgroundColor,
125- radius = radius,
126- center = Offset (canvasWidth - radius, canvasHeight / 2 ),
127- )
128- }
129- }
13073
13174 val coefficient = 360f / count
13275
13376 // Dynamic items
134- for (i in 0 .. count) {
77+ for (i in 0 .. count / 2 ) {
13578 rotate((angle.toInt() + i) * coefficient) {
136- drawCircle(
137- color = foregroundColor.copy(
138- alpha = (i.toFloat() / count).coerceIn(
139- 0f ,
140- 1f
141- )
142- ),
143- radius = radius,
144- center = Offset (canvasWidth - radius, canvasHeight / 2 ),
145- )
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+ }
146101 }
147102 }
148- }
149103 }
150104}
151105
152- @Composable
153- fun ScaledCircleProgressIndicator (
154- modifier : Modifier = Modifier
155- ) {
156- val count = 8f
157-
158- val infiniteTransition = rememberInfiniteTransition()
159- val angle by infiniteTransition.animateFloat(
160- initialValue = 0f ,
161- targetValue = count,
162- infiniteRepeatable(
163- animation = keyframes {
164- durationMillis = 1100
165- count * 0.8f at 700
166- count * 0.1f at 150 with FastOutLinearInEasing
167- count * 0.10f at 150
168- }
169- )
170- )
171-
172- val foregroundColor = Color .Red
173-
174- val radiusList = remember { arrayListOf<Float >() }
175-
176- Canvas (
177- modifier = modifier
178- .size(100 .dp)
179- .border(1 .dp, Color .Red )
180- ) {
181-
182- val canvasWidth = size.width
183- val canvasHeight = size.height
184-
185-
186- val coefficient = 360f / count
187-
188- val radiusMax = canvasWidth / 2 * .1f
189-
190- if (radiusList.isEmpty()) {
191- repeat(6 ) {
192- if (it == 0 ) {
193- radiusList.add(radiusMax)
194- } else {
195- radiusList.add(radiusList[it - 1 ] * 1.2f )
196- }
197- }
198- }
199-
200- val radiusDynamicContainer = (canvasWidth - radiusList.last())
201-
202-
203- // Dynamic items
204- for (i in 0 until radiusList.size) {
205-
206- val radius = radiusList[i]
207-
208- rotate((angle + i) * coefficient) {
209- drawCircle(
210- color = foregroundColor.copy(alpha = ( i * .2f ).coerceIn(0f , 1f )),
211- radius = radius,
212- center = Offset (radiusDynamicContainer, canvasHeight / 2 ),
213- )
214- }
215- }
216- }
217- }
0 commit comments