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
相关产品推荐
相关产品推荐

