You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:如何在DrawScope中调用@Composable加载动画函数?

解决DrawScope中无法调用@Composable函数的加载条实现问题

你遇到的问题核心是:DrawScope不属于@Composable上下文,所以不能在Canvas的代码块里调用任何@Composable函数。下面给两种可行的解决方案:

方案一:用Box叠加Canvas和加载组件(推荐)

把Canvas和加载状态的Composable组件放在同一个Box中,通过model.isLoading控制显示逻辑,这样加载组件的调用就回到了@Composable上下文里:

@Composable
fun Chart(
    modifier: Modifier = Modifier,
    model: BarData
) {
    Column(modifier = modifier) {
        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
        ) {
            // 原有的Canvas绘制逻辑
            Canvas(modifier = Modifier.fillMaxSize()) {
                val radius = 45f
                
                val (paidBarHeight, incomingBarHeight) = computeBarsHeights(
                    paidRatioAnim,
                    incomingRatioAnim,
                    size
                )

                if(!model.isLoading) {
                    rotate(180f, pivot = size.center) {
                        drawRoundRect(
                            color = ChartBackgroundGreyColor,
                            size = size.copy(height = incomingBarHeight),
                            cornerRadius = CornerRadius(radius, radius)
                        )
                        drawRoundRect(
                            color = ChartBasicGreenColor,
                            size = size.copy(height = paidBarHeight),
                            cornerRadius = CornerRadius(radius, radius)
                        )
                    }
                }
            }
            
            // 加载状态下显示的组件,直接放在Box中覆盖Canvas
            if(model.isLoading) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    // 可以用系统自带的加载指示器,也可以替换成自定义加载条
                    CircularProgressIndicator(color = ChartBasicGreenColor)
                }
            }
        }
    }
}

方案二:在DrawScope中直接绘制带动画的加载条

如果需要加载条和原有图表风格完全统一,可以在@Composable函数中创建动画状态,然后在DrawScope里使用动画值直接绘制动态加载效果:

@Composable
fun Chart(
    modifier: Modifier = Modifier,
    model: BarData
) {
    // 创建无限循环的动画值,控制加载条进度
    val loadingProgress by animateFloatAsState(
        targetValue = if(model.isLoading) 1f else 0f,
        animationSpec = infiniteRepeatable(
            animation = tween(1000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "loading progress"
    )
    
    Column(modifier = modifier) {
        Canvas(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
        ) {
            val radius = 45f
            
            val (paidBarHeight, incomingBarHeight) = computeBarsHeights(
                paidRatioAnim,
                incomingRatioAnim,
                size
            )

            if(!model.isLoading) {
                rotate(180f, pivot = size.center) {
                    drawRoundRect(
                        color = ChartBackgroundGreyColor,
                        size = size.copy(height = incomingBarHeight),
                        cornerRadius = CornerRadius(radius, radius)
                    )
                    drawRoundRect(
                        color = ChartBasicGreenColor,
                        size = size.copy(height = paidBarHeight),
                        cornerRadius = CornerRadius(radius, radius)
                    )
                }
            } else {
                // 绘制自定义带动画的加载条
                val barWidth = size.width * 0.8f
                val barHeight = 20f
                val barX = (size.width - barWidth) / 2
                val barY = (size.height - barHeight) / 2
                
                // 加载条背景
                drawRoundRect(
                    color = ChartBackgroundGreyColor,
                    topLeft = Offset(barX, barY),
                    size = Size(barWidth, barHeight),
                    cornerRadius = CornerRadius(10f)
                )
                
                // 动态变化的加载进度条
                val progressWidth = barWidth * loadingProgress
                drawRoundRect(
                    color = ChartBasicGreenColor,
                    topLeft = Offset(barX, barY),
                    size = Size(progressWidth, barHeight),
                    cornerRadius = CornerRadius(10f)
                )
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Wafi_ck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:53:24