android 合成中圆角的圆形进度指示器

w41d8nur  于 2023-01-15  发布在  Android
关注(0)|答案(5)|浏览(200)

我试图用jetpack组合圆化CircularProgressIndicator的角。但我没有看到任何成员变量这样做。以下是源代码,但它不把Stroke作为参数。如果它可以,那么我们将能够创建一个圆帽自定义Stroke。

@Composable
fun CircularProgressIndicator(
    /*@FloatRange(from = 0.0, to = 1.0)*/
    progress: Float,
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colors.primary,
    strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth
) {
    val stroke = with(LocalDensity.current) {
        Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Butt)
    }
    Canvas(
        modifier
            .progressSemantics(progress)
            .size(CircularIndicatorDiameter)
            .focusable()
    ) {
        // Start at 12 O'clock
        val startAngle = 270f
        val sweep = progress * 360f
        drawDeterminateCircularIndicator(startAngle, sweep, color, stroke)
    }
}
ego6inou

ego6inou1#

大写是硬编码在源函数中的。我使用的解决方案基本上是复制粘贴源函数和改变笔划大写。同样对于线性指示器,你需要做一些额外的数学运算,这样圆形大写就不会超过指定的宽度。

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ProgressIndicatorDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp

private val LinearIndicatorWidth = 240.dp
private val LinearIndicatorHeight = ProgressIndicatorDefaults.StrokeWidth

private val CircularIndicatorDiameter = 40.dp

@Composable
internal fun RoundedLinearProgressIndicator(
    /*@FloatRange(from = 0.0, to = 1.0)*/
    progress: Float,
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colors.primary,
    backgroundColor: Color = color.copy(alpha = ProgressIndicatorDefaults.IndicatorBackgroundOpacity)
) {
    Canvas(
        modifier
            .progressSemantics(progress)
            .size(LinearIndicatorWidth, LinearIndicatorHeight)
            .focusable()
    ) {
        val strokeWidth = size.height
        drawRoundedLinearProgressIndicator(
            startFraction = 0f,
            endFraction = 1f,
            color = backgroundColor,
            strokeWidth = strokeWidth
        )
        drawRoundedLinearProgressIndicator(
            startFraction = 0f,
            endFraction = progress,
            color = color,
            strokeWidth = strokeWidth
        )
    }
}

@Composable
internal fun RoundedCircularProgressIndicator(
    /*@FloatRange(from = 0.0, to = 1.0)*/
    progress: Float,
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colors.primary,
    strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth
) {
    val stroke = with(LocalDensity.current) {
        Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Round)
    }
    Canvas(
        modifier
            .progressSemantics(progress)
            .size(CircularIndicatorDiameter)
            .focusable()
    ) {
        // Start at 12 O'clock
        val startAngle = 270f
        val sweep = progress * 360f
        drawRoundedCircularIndicator(startAngle, sweep, color, stroke)
    }
}

private fun DrawScope.drawRoundedCircularIndicator(
    startAngle: Float,
    sweep: Float,
    color: Color,
    stroke: Stroke
) {
    // To draw this circle we need a rect with edges that line up with the midpoint of the stroke.
    // To do this we need to remove half the stroke width from the total diameter for both sides.
    val diameterOffset = stroke.width / 2
    val arcDimen = size.width - 2 * diameterOffset
    drawArc(
        color = color,
        startAngle = startAngle,
        sweepAngle = sweep,
        useCenter = false,
        topLeft = Offset(diameterOffset, diameterOffset),
        size = Size(arcDimen, arcDimen),
        style = stroke
    )
}

private fun DrawScope.drawRoundedLinearProgressIndicator(
    startFraction: Float,
    endFraction: Float,
    color: Color,
    strokeWidth: Float,
) {
    val cap = StrokeCap.Round
    val width = size.width
    val height = size.height
    // Start drawing from the vertical center of the stroke
    val yOffset = height / 2

    val roundedCapOffset = size.height / 2

    val isLtr = layoutDirection == LayoutDirection.Ltr
    val barStart = (if (isLtr) startFraction else 1f - endFraction) * width + if (isLtr) roundedCapOffset else -roundedCapOffset
    val barEnd = (if (isLtr) endFraction else 1f - startFraction) * width - if (isLtr) roundedCapOffset else -roundedCapOffset

    // Progress line
    drawLine(
        color = color,
        start = Offset(barStart, yOffset),
        end = Offset(barEnd, yOffset),
        strokeWidth = strokeWidth,
        cap = cap,
    )
}
zd287kbt

zd287kbt2#

我的全面进步是这样的:

LinearProgressIndicator(
    modifier = Modifier
    .background(Color.Transparent)
    .clip(CircleShape)
    .height(16.dp),
    progress = 1f
)
5vf7fwbs

5vf7fwbs3#

作为一个想法,你可以只画两个圆圈以上的进展

@Composable
fun RoundedCircularProgress(
        progress: Float,
        strokeWidth: Dp,
        progressColor: Color,
        modifier: Modifier = Modifier
) {
    Box(modifier = modifier.size(100.dp)) {
        // circle progress
        CircularProgressIndicator(
                progress = progress,
                color = progressColor,
                strokeWidth = strokeWidth,
                modifier = Modifier.fillMaxSize()
        )
        // start circle
        Spacer(modifier = Modifier
                .fillMaxSize()
                .wrapContentSize(align = Alignment.TopCenter)
                .size(strokeWidth)
                .background(progressColor, CircleShape)
        )
        // end circle
        Spacer(modifier = Modifier
                .fillMaxSize()
                .rotate(360 * progress)
                .wrapContentSize(align = Alignment.TopCenter)
                .size(strokeWidth)
                .background(progressColor, CircleShape)
        )
    }
}
nue99wik

nue99wik4#

只需像这样将剪辑添加到LinearProgressIndicator
modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(14.dp))

3duebb1j

3duebb1j5#

从M2 1.4.0-alpha04和M3 1.1.0-alpha04开始,您可以使用**strokeCap**参数:

CircularProgressIndicator(
        //...
        strokeCap  = StrokeCap.Round,
    )

相关问题