From 3c8ff4d0fb7a48b945800c0692190938aec9f08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E9=93=AD=E6=9D=B0?= Date: Wed, 13 Sep 2023 14:51:46 +0800 Subject: [PATCH] feat:Basic Progress Indicator Finished --- .../src/commonMain/kotlin/App.kt | 31 +---- .../kotlin/progressindicator/DrawScopeExt.kt | 37 ++++++ .../SimpleProgressIndicator.kt | 111 +++++++++++++++++ .../SimpleProgressIndicatorDefaults.kt | 23 ++++ .../sample/BasicProgressIndicatorSample.kt | 116 ++++++++++++++++++ 5 files changed, 289 insertions(+), 29 deletions(-) create mode 100644 progressIndicator/src/commonMain/kotlin/progressindicator/DrawScopeExt.kt create mode 100644 progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicator.kt create mode 100644 progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicatorDefaults.kt create mode 100644 progressIndicator/src/commonMain/kotlin/sample/BasicProgressIndicatorSample.kt diff --git a/progressIndicator/src/commonMain/kotlin/App.kt b/progressIndicator/src/commonMain/kotlin/App.kt index 0889bdd..69ca5a6 100644 --- a/progressIndicator/src/commonMain/kotlin/App.kt +++ b/progressIndicator/src/commonMain/kotlin/App.kt @@ -1,40 +1,13 @@ -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource +import sample.BasicProgressIndicatorSample @OptIn(ExperimentalResourceApi::class) @Composable fun App() { MaterialTheme { - var greetingText by remember { mutableStateOf("Hello, World!") } - var showImage by remember { mutableStateOf(false) } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Button(onClick = { - greetingText = "Hello, ${getPlatformName()}" - showImage = !showImage - }) { - Text(greetingText) - } - AnimatedVisibility(showImage) { - Image( - painterResource("compose-multiplatform.xml"), - null - ) - } - } + BasicProgressIndicatorSample() } } diff --git a/progressIndicator/src/commonMain/kotlin/progressindicator/DrawScopeExt.kt b/progressIndicator/src/commonMain/kotlin/progressindicator/DrawScopeExt.kt new file mode 100644 index 0000000..049ac73 --- /dev/null +++ b/progressIndicator/src/commonMain/kotlin/progressindicator/DrawScopeExt.kt @@ -0,0 +1,37 @@ +package progressindicator + +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.unit.Dp + +/** + * Created By Kevin Zou On 2023/9/13 + */ +internal fun DrawScope.drawLinearIndicatorBackground( + color: Color, + cornerRadius: Dp +) { + drawLinearIndicator(1f, color, cornerRadius) +} + +internal fun DrawScope.drawLinearIndicator( + widthFraction: Float, + color: Color, + cornerRadius: Dp, +) { + drawRoundRect( + color = color, + size = drawContext.size.copy(width = size.width * widthFraction), + cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx()) + ) +} + +internal fun DrawScope.drawThumb(radius: Dp, color: Color, center: Offset) { + drawCircle( + color, + radius = radius.toPx(), + center = center + ) +} \ No newline at end of file diff --git a/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicator.kt b/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicator.kt new file mode 100644 index 0000000..f97c54d --- /dev/null +++ b/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicator.kt @@ -0,0 +1,111 @@ +package progressindicator + +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.progressSemantics +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +/** + * Created By Kevin Zou On 2023/9/13 + */ + +/** + * Determinate Material Design linear progress indicator. + * + * Progress indicators express an unspecified wait time or display the length of a process. + * + * @param progress The progress of this progress indicator, where 0.0 represents no progress and 1.0 + * represents full progress. Values outside of this range are coerced into the range. + * @param progressBarColor The color of the progress indicator. + * @param cornerRadius The corner radius of the progress indicator. + * @param trackColor The color of the background behind the indicator, visible when the + * progress has not reached that area of the overall indicator yet. + * @param thumbRadius The radius of the thumb of the progress indicator. + * @param thumbColor The color of the thumb of the progress indicator. + * @param thumbOffset The offset of the thumb of the progress indicator. It determines the center of the + * thumb. If the offset is zero, the center of the thumb will be at the end of the progress. By default, it is + * set to [thumbRadius] so that it will coerce into the progressbar. + * @param animationSpec The animation specifics for progress change. + */ +@Composable +fun SimpleProgressIndicatorWithAnim( + modifier: Modifier = Modifier, + progress: Float = 0.7f, + progressBarColor: Color = Color.Red, + cornerRadius: Dp = 0.dp, + trackColor: Color = Color(0XFFFBE8E8), + thumbRadius: Dp = 0.dp, + thumbColor: Color = Color.White, + thumbOffset: Dp = thumbRadius, + animationSpec: AnimationSpec = SimpleProgressIndicatorDefaults.SimpleProgressAnimationSpec, +) { + val mProgress: Float by animateFloatAsState( + targetValue = progress, + animationSpec = animationSpec + ) + SimpleProgressIndicator( + modifier, + mProgress, + progressBarColor, + cornerRadius, + trackColor, + thumbRadius, + thumbColor, + thumbOffset + ) +} + + +/** + * Determinate Material Design linear progress indicator. + * + * Progress indicators express an unspecified wait time or display the length of a process. + * + * By default there is no animation between [progress] values. You can use + * [SimpleProgressIndicatorWithAnim] to animate progress. + * + * @param progress The progress of this progress indicator, where 0.0 represents no progress and 1.0 + * represents full progress. Values outside of this range are coerced into the range. + * @param progressBarColor The color of the progress indicator. + * @param cornerRadius The corner radius of the progress indicator. + * @param trackColor The color of the background behind the indicator, visible when the + * progress has not reached that area of the overall indicator yet. + * @param thumbRadius The radius of the thumb of the progress indicator. + * @param thumbColor The color of the thumb of the progress indicator. + * @param thumbOffset The offset of the thumb of the progress indicator. It determines the center of the + * thumb. If the offset is zero, the center of the thumb will be at the end of the progress. By default, it is + * set to [thumbRadius] so that it will coerce into the progressbar. + */ +@Composable +fun SimpleProgressIndicator( + modifier: Modifier = Modifier, + progress: Float = 0.7f, + progressBarColor: Color = Color.Red, + cornerRadius: Dp = 0.dp, + trackColor: Color = Color(0XFFFBE8E8), + thumbRadius: Dp = 0.dp, + thumbColor: Color = Color.White, + thumbOffset: Dp = thumbRadius +) { + Canvas(modifier.progressSemantics(progress)) { + val progressWidth = size.width * progress + drawLinearIndicatorBackground(trackColor, cornerRadius) + drawLinearIndicator(progress, progressBarColor, cornerRadius) + val thumbCenter = progressWidth - thumbOffset.toPx() + if (thumbCenter > 0) { + drawThumb( + thumbRadius, + thumbColor, + Offset(progressWidth - thumbOffset.toPx(), size.height / 2f) + ) + } + + } +} \ No newline at end of file diff --git a/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicatorDefaults.kt b/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicatorDefaults.kt new file mode 100644 index 0000000..47bfc2a --- /dev/null +++ b/progressIndicator/src/commonMain/kotlin/progressindicator/SimpleProgressIndicatorDefaults.kt @@ -0,0 +1,23 @@ +package progressindicator + +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring + +/** + * Created By Kevin Zou On 2023/9/13 + */ +/** + * Contains the default values used for [SimpleProgressIndicator]. + */ +object SimpleProgressIndicatorDefaults { + /** + * The default [AnimationSpec] that should be used when animating between progress in a + * determinate progress indicator. + */ + val SimpleProgressAnimationSpec: AnimationSpec = spring( + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessLow, + visibilityThreshold = null, + ) +} \ No newline at end of file diff --git a/progressIndicator/src/commonMain/kotlin/sample/BasicProgressIndicatorSample.kt b/progressIndicator/src/commonMain/kotlin/sample/BasicProgressIndicatorSample.kt new file mode 100644 index 0000000..05b495c --- /dev/null +++ b/progressIndicator/src/commonMain/kotlin/sample/BasicProgressIndicatorSample.kt @@ -0,0 +1,116 @@ +package sample + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.LinearProgressIndicator +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import progressindicator.SimpleProgressIndicatorWithAnim + +/** + * Created By Kevin Zou On 2023/9/13 + */ +@Composable +fun BasicProgressIndicatorSample() { + var progress by remember { mutableStateOf(0.5f) } + Surface( + modifier = Modifier.fillMaxSize(), + color = Color.White + ) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Column( + modifier = Modifier.wrapContentSize(), + verticalArrangement = Arrangement.spacedBy(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text("Simple ProgressIndicator Examples", fontSize = 16.sp) + LinearProgressIndicator( + progress, modifier = Modifier + .padding(15.dp) + .fillMaxWidth() + .height(12.dp) + ) + SimpleProgressIndicatorWithAnim( + modifier = Modifier + .padding(15.dp) + .fillMaxWidth() + .height(12.dp), + progress = progress, + trackColor = Color(0XFFFBE8E8), + progressBarColor = Color.Yellow, + thumbColor = Color.Magenta, + cornerRadius = 15.dp, + thumbRadius = 6.dp, + thumbOffset = 6.dp, + animationSpec = spring( + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessVeryLow, + visibilityThreshold = 0.4f, + ) + ) + SimpleProgressIndicatorWithAnim( + modifier = Modifier + .padding(15.dp) + .fillMaxWidth() + .height(12.dp), + progress, + cornerRadius = 15.dp, + thumbRadius = 5.dp, + thumbOffset = 6.dp + ) + Row( + modifier = Modifier + .height(50.dp) + .wrapContentWidth(), + horizontalArrangement = Arrangement.spacedBy(50.dp) + ) { + Button( + onClick = { + progress = (progress - 0.1f).coerceAtLeast(0f) + }, + shape = RoundedCornerShape(10.dp), + ) { + Text(text = "Decrease") + } + Button( + onClick = { + progress = (progress + 0.1f).coerceAtMost(1f) + }, + shape = RoundedCornerShape(10.dp), + ) { + Text(text = "Increase") + } + } + } + } + + } +} \ No newline at end of file