11package com.smarttoolfactory.tutorial1_1basics.chapter6_graphics
22
3+ import androidx.compose.animation.core.Animatable
34import androidx.compose.animation.core.LinearEasing
45import androidx.compose.animation.core.animateFloatAsState
56import androidx.compose.animation.core.tween
@@ -13,15 +14,22 @@ import androidx.compose.foundation.layout.height
1314import androidx.compose.foundation.layout.padding
1415import androidx.compose.foundation.layout.size
1516import androidx.compose.material.Button
17+ import androidx.compose.material.Slider
1618import androidx.compose.material.Text
19+ import androidx.compose.material.icons.Icons
20+ import androidx.compose.material.icons.filled.CarRental
21+ import androidx.compose.material3.Icon
1722import androidx.compose.runtime.Composable
1823import androidx.compose.runtime.LaunchedEffect
24+ import androidx.compose.runtime.derivedStateOf
1925import androidx.compose.runtime.getValue
2026import androidx.compose.runtime.mutableStateOf
2127import androidx.compose.runtime.remember
28+ import androidx.compose.runtime.rememberCoroutineScope
2229import androidx.compose.runtime.setValue
2330import androidx.compose.ui.Alignment
2431import androidx.compose.ui.Modifier
32+ import androidx.compose.ui.draw.drawBehind
2533import androidx.compose.ui.geometry.CornerRadius
2634import androidx.compose.ui.geometry.Offset
2735import androidx.compose.ui.geometry.Rect
@@ -35,6 +43,7 @@ import androidx.compose.ui.tooling.preview.Preview
3543import androidx.compose.ui.unit.dp
3644import androidx.compose.ui.unit.sp
3745import kotlinx.coroutines.delay
46+ import kotlinx.coroutines.launch
3847import kotlin.math.roundToInt
3948
4049@Preview
@@ -46,6 +55,11 @@ fun Tutorial6_13Screen() {
4655@Composable
4756private fun TutorialContent () {
4857
58+ BorderProgressSample1 ()
59+ // BorderProgressSample2()
60+ }
61+
62+ private fun BorderProgressSample1 () {
4963 val startDurationInSeconds = 20
5064 var currentTime by remember {
5165 mutableStateOf(startDurationInSeconds)
@@ -256,4 +270,91 @@ private fun TutorialContent() {
256270 )
257271
258272 }
273+ }
274+
275+ @Preview
276+ @Composable
277+ fun BorderProgressSample2 () {
278+
279+ val pathMeasure by remember { mutableStateOf(PathMeasure ()) }
280+
281+ val path = remember {
282+ Path ()
283+ }
284+
285+ val pathWithProgress by remember {
286+ mutableStateOf(Path ())
287+ }
288+
289+ val animatable = remember {
290+ Animatable (0f )
291+ }
292+
293+ val isFilled by remember {
294+ derivedStateOf { animatable.value == 100f }
295+ }
296+
297+ val coroutineScope = rememberCoroutineScope()
298+
299+ Column (
300+ modifier = Modifier .fillMaxSize().padding(16 .dp)
301+ ) {
302+
303+ // Text("Progress: ${animatable.value.toInt()}")
304+ Slider (
305+ value = animatable.value,
306+ onValueChange = {
307+ coroutineScope.launch {
308+ animatable.animateTo(it)
309+ }
310+ },
311+ valueRange = 0f .. 100f
312+ )
313+
314+ Icon (
315+ modifier = Modifier .size(128 .dp)
316+ .drawBehind {
317+
318+ if (path.isEmpty) {
319+ path.addRoundRect(
320+ RoundRect (
321+ Rect (offset = Offset .Zero , size),
322+ cornerRadius = CornerRadius (16 .dp.toPx(), 16 .dp.toPx())
323+ )
324+ )
325+
326+ pathMeasure.setPath(path, forceClosed = false )
327+ }
328+
329+ pathWithProgress.reset()
330+
331+ pathMeasure.setPath(path, forceClosed = false )
332+ pathMeasure.getSegment(
333+ startDistance = 0f ,
334+ stopDistance = pathMeasure.length * animatable.value / 100f ,
335+ pathWithProgress,
336+ startWithMoveTo = true
337+ )
338+
339+ drawPath(
340+ path = path,
341+ style = Stroke (
342+ 4 .dp.toPx()
343+ ),
344+ color = Color .Black
345+ )
346+
347+ drawPath(
348+ path = pathWithProgress,
349+ style = Stroke (
350+ 4 .dp.toPx()
351+ ),
352+ color = Color .Blue
353+ )
354+ },
355+ tint = if (isFilled) Color .Blue else Color .Black ,
356+ imageVector = Icons .Default .CarRental ,
357+ contentDescription = null
358+ )
359+ }
259360}
0 commit comments