1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.graphics.shapes.testcompose
18
19 import android.os.Bundle
20 import androidx.activity.compose.setContent
21 import androidx.compose.animation.core.Animatable
22 import androidx.compose.animation.core.AnimationVector1D
23 import androidx.compose.animation.core.LinearEasing
24 import androidx.compose.animation.core.RepeatMode
25 import androidx.compose.animation.core.infiniteRepeatable
26 import androidx.compose.animation.core.tween
27 import androidx.compose.foundation.clickable
28 import androidx.compose.foundation.layout.Box
29 import androidx.compose.foundation.layout.Column
30 import androidx.compose.foundation.layout.fillMaxSize
31 import androidx.compose.material3.MaterialTheme
32 import androidx.compose.material3.Slider
33 import androidx.compose.runtime.Composable
34 import androidx.compose.runtime.mutableFloatStateOf
35 import androidx.compose.runtime.remember
36 import androidx.compose.runtime.rememberCoroutineScope
37 import androidx.compose.ui.Modifier
38 import androidx.compose.ui.draw.drawWithContent
39 import androidx.compose.ui.graphics.Color
40 import androidx.compose.ui.graphics.Matrix
41 import androidx.compose.ui.graphics.Path
42 import androidx.compose.ui.graphics.PathMeasure
43 import androidx.compose.ui.graphics.asComposePath
44 import androidx.compose.ui.graphics.drawscope.Stroke
45 import androidx.fragment.app.FragmentActivity
46 import androidx.graphics.shapes.CornerRounding
47 import androidx.graphics.shapes.RoundedPolygon
48 import androidx.graphics.shapes.pillStar
49 import androidx.graphics.shapes.toPath
50 import kotlinx.coroutines.launch
51
52 /**
53 * This is a simple app showing how to use the startLocation parameter to change where a pillStar
54 * shape starts from, then animating a stroked path from that starting point.
55 */
56 class ProgressActivity : FragmentActivity() {
onCreatenull57 override fun onCreate(savedInstanceState: Bundle?) {
58 super.onCreate(savedInstanceState)
59 setContent(parent = null) { MaterialTheme { ProgressHolder() } }
60 }
61 }
62
63 @Composable
ProgressHoldernull64 fun ProgressHolder() {
65 val progress = remember { Animatable(1f) }
66 val startLocation = remember { mutableFloatStateOf(0f) }
67 val pillStar =
68 RoundedPolygon.pillStar(
69 numVerticesPerRadius = 16,
70 width = 1.8f,
71 height = .4f,
72 rounding = CornerRounding(1f),
73 startLocation = startLocation.floatValue
74 )
75 val scope = rememberCoroutineScope()
76 val pathMeasure = PathMeasure()
77 val pathSegment = Path()
78
79 Column {
80 Slider(
81 value = startLocation.floatValue.coerceIn(0f, 1f),
82 onValueChange = { startLocation.floatValue = it }
83 )
84 Box(
85 Modifier.clickable { scope.launch { doAnimation(progress) } }
86 .fillMaxSize()
87 .drawWithContent {
88 drawContent()
89 val scale = size.minDimension / 2
90 val m = Matrix()
91 m.translate(size.width / 2, size.height / 2, 0f)
92 m.scale(scale, scale)
93
94 val pillStarPath = pillStar.toPath().asComposePath()
95 pillStarPath.transform(m)
96 pathMeasure.setPath(pillStarPath, false)
97 val pathLength = pathMeasure.length
98 pathSegment.rewind()
99 pathMeasure.getSegment(0f, progress.value * pathLength, pathSegment, true)
100 drawPath(path = pathSegment, style = Stroke(20f), color = Color.Blue)
101 }
102 )
103 }
104 }
105
doAnimationnull106 private suspend fun doAnimation(progress: Animatable<Float, AnimationVector1D>) {
107 progress.snapTo(0f)
108 progress.animateTo(
109 1f,
110 infiniteRepeatable(tween(1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse)
111 )
112 }
113