Skip to content

Commit c3cbc80

Browse files
add dot progress indicators
1 parent 946f9aa commit c3cbc80

File tree

5 files changed

+176
-3
lines changed

5 files changed

+176
-3
lines changed

app/src/main/java/com/smarttoolfactory/composeprogressindicator/MainActivity.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.smarttoolfactory.composeprogressindicator
33
import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
6+
import androidx.compose.foundation.layout.Column
67
import androidx.compose.foundation.layout.fillMaxSize
78
import androidx.compose.material3.MaterialTheme
89
import androidx.compose.material3.Surface
@@ -20,7 +21,9 @@ class MainActivity : ComponentActivity() {
2021
modifier = Modifier.fillMaxSize(),
2122
color = MaterialTheme.colorScheme.background
2223
) {
23-
ProgressIndicatorDemo()
24+
Column {
25+
ProgressIndicatorDemo()
26+
}
2427
}
2528
}
2629
}

app/src/main/java/com/smarttoolfactory/composeprogressindicator/ProgressIndicatorDemo.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.smarttoolfactory.progressindicator.*
1414
fun ProgressIndicatorDemo() {
1515
Column(
1616
modifier = Modifier
17+
.fillMaxSize()
1718
.background(Color.DarkGray)
1819
.padding(10.dp)
1920
) {
@@ -96,6 +97,31 @@ fun ProgressIndicatorDemo() {
9697
color = Color(0xffEC407A)
9798
)
9899
}
99-
}
100100

101+
Spacer(modifier = Modifier.height(10.dp))
102+
Row(
103+
modifier = Modifier.fillMaxWidth(),
104+
verticalAlignment = Alignment.CenterVertically
105+
) {
106+
DotProgressIndicator()
107+
Spacer(modifier = Modifier.width(10.dp))
108+
DotProgressIndicator(
109+
initialColor = Color(0xffF44336),
110+
animatedColor = Color(0xff29B6F6)
111+
)
112+
}
113+
114+
Spacer(modifier = Modifier.height(10.dp))
115+
Row(
116+
modifier = Modifier.fillMaxWidth(),
117+
verticalAlignment = Alignment.CenterVertically
118+
) {
119+
BouncingDotProgressIndicator()
120+
Spacer(modifier = Modifier.width(10.dp))
121+
BouncingDotProgressIndicator(
122+
initialColor = Color(0xffF44336),
123+
animatedColor = Color(0xff29B6F6)
124+
)
125+
}
126+
}
101127
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package com.smarttoolfactory.progressindicator
2+
3+
import androidx.compose.animation.core.*
4+
import androidx.compose.foundation.Canvas
5+
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.foundation.layout.size
7+
import androidx.compose.runtime.Composable
8+
import androidx.compose.runtime.LaunchedEffect
9+
import androidx.compose.runtime.remember
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.geometry.Offset
12+
import androidx.compose.ui.graphics.Color
13+
import androidx.compose.ui.graphics.lerp
14+
import androidx.compose.ui.unit.dp
15+
16+
@Composable
17+
fun BouncingDotProgressIndicator(
18+
modifier: Modifier = Modifier,
19+
initialColor: Color = IndicatorDefaults.DotColor,
20+
animatedColor: Color = IndicatorDefaults.DotColor
21+
) {
22+
val dotAnimatables = remember {
23+
listOf(
24+
Animatable(0f),
25+
Animatable(0f),
26+
Animatable(0f)
27+
)
28+
}
29+
dotAnimatables.forEachIndexed { index, animatable ->
30+
31+
LaunchedEffect(key1 = animatable) {
32+
animatable.animateTo(
33+
targetValue = 1f, animationSpec = infiniteRepeatable(
34+
initialStartOffset = StartOffset(index * 150),
35+
animation = keyframes {
36+
durationMillis = 1000
37+
0.0f at 0 with LinearOutSlowInEasing
38+
1.0f at 300 with LinearOutSlowInEasing
39+
0f at 700 with LinearOutSlowInEasing
40+
0f at 1000
41+
},
42+
repeatMode = RepeatMode.Restart,
43+
)
44+
)
45+
}
46+
}
47+
48+
val sameColor = initialColor == animatedColor
49+
50+
Canvas(
51+
modifier = modifier
52+
.size(96.dp, 48.dp)
53+
.padding(8.dp)
54+
) {
55+
val canvasWidth = size.width
56+
57+
val space = canvasWidth * 0.1f
58+
val diameter = (canvasWidth - 2 * space) / 3
59+
val radius = diameter / 2
60+
61+
dotAnimatables.forEachIndexed { index, animatable ->
62+
val x = radius + index * (diameter + space)
63+
val value = animatable.value
64+
65+
drawCircle(
66+
color = if (sameColor) initialColor else lerp(
67+
initialColor,
68+
animatedColor,
69+
value
70+
),
71+
center = Offset(
72+
x = x,
73+
y = center.y - radius * value * 1.6f
74+
),
75+
radius = radius
76+
)
77+
}
78+
}
79+
}
80+
81+
@Composable
82+
fun DotProgressIndicator(
83+
modifier: Modifier = Modifier,
84+
initialColor: Color = IndicatorDefaults.DotColor,
85+
animatedColor: Color = IndicatorDefaults.DotColor
86+
) {
87+
88+
val dotAnimatables = remember {
89+
listOf(
90+
Animatable(0.25f),
91+
Animatable(0.25f),
92+
Animatable(0.25f)
93+
)
94+
}
95+
dotAnimatables.forEachIndexed { index, animatable ->
96+
97+
LaunchedEffect(key1 = animatable) {
98+
animatable.animateTo(
99+
targetValue = 1f,
100+
animationSpec = infiniteRepeatable(
101+
initialStartOffset = StartOffset(index * 300),
102+
animation = tween(600, easing = FastOutLinearInEasing),
103+
repeatMode = RepeatMode.Reverse,
104+
)
105+
)
106+
}
107+
}
108+
109+
val sameColor = initialColor == animatedColor
110+
111+
Canvas(
112+
modifier = modifier
113+
.size(96.dp, 48.dp)
114+
.padding(8.dp)
115+
) {
116+
val canvasWidth = size.width
117+
val canvasHeight = size.height
118+
119+
val diameter = (canvasHeight / 2).coerceAtLeast(canvasWidth / 3)
120+
val radius = diameter / 2
121+
122+
dotAnimatables.forEachIndexed { index, animatable ->
123+
val x = radius + index * (diameter)
124+
val value = animatable.value
125+
126+
127+
drawCircle(
128+
color = if (sameColor) initialColor.copy(alpha = value) else
129+
lerp(
130+
initialColor,
131+
animatedColor,
132+
value
133+
),
134+
center = Offset(
135+
x = x,
136+
y = center.y
137+
),
138+
radius = radius * value
139+
)
140+
}
141+
}
142+
}

progressindicator/src/main/java/com/smarttoolfactory/progressindicator/GooeyProgressIndicator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ private fun StrokeGooeyImpl(
248248

249249
drawPath(
250250
path = pathDynamic,
251-
color = Color.Red,
251+
color = Color(0xffE1BEE7),
252252
style = Stroke(1.dp.toPx(), pathEffect = chainPathEffect)
253253
)
254254
}

progressindicator/src/main/java/com/smarttoolfactory/progressindicator/IndicatorDefaults.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ object IndicatorDefaults {
1212
Color(0xffFFEB3B),
1313
Color(0xffE91E63)
1414
)
15+
16+
val DotColor = Color(0xffBDBDBD)
1517
}
1618

1719
enum class SpinnerShape {

0 commit comments

Comments
 (0)