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

Compose库升级至最新版本后,内部字段无法访问的错误如何修复?

Compose升级后内部API访问错误的修复方案

一、SwipeButton组件修复

问题场景

升级Compose库后,ButtonColors和ButtonElevation的部分方法被标记为内部API,直接调用contentColor()、containerColor()、shadowElevation()、tonalElevation()会触发访问权限错误。

报错信息

Cannot access 'contentColor': it is internal in 'ButtonColors'
Cannot access 'containerColor': it is internal in 'ButtonColors'
Cannot access 'shadowElevation': it is internal in 'ButtonElevation'
Cannot access 'tonalElevation': it is internal in 'ButtonElevation'

修复后的代码

@Composable
fun SwipeButton(
    onSwiped: () -> Unit,
    modifier: Modifier = Modifier,
    swipeButtonState: SwipeButtonState,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
    shape: Shape = RoundedCornerShape(20.0.dp),
    border: BorderStroke? = null,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    icon: ImageVector = Icons.Default.ArrowForward,
    rotateIcon: Boolean = true,
    iconPadding: PaddingValues = PaddingValues(2.dp),
    content: @Composable RowScope.() -> Unit
) {
    // 替换原内部API调用,使用公开的resolve方法获取颜色和elevation结果
    val buttonColorsResult by remember(enabled, interactionSource) {
        derivedStateOf { colors.resolve(enabled, interactionSource) }
    }
    val contentColor = buttonColorsResult.contentColor
    val elevationResult by remember(enabled, interactionSource) {
        derivedStateOf { elevation?.resolve(enabled, interactionSource) }
    }

    val dragOffset = remember { mutableStateOf(0f) }

    val collapsed = swipeButtonState == SwipeButtonState.COLLAPSED
    val swiped = swipeButtonState == SwipeButtonState.SWIPED

    Surface(
        modifier = modifier,
        shape = shape,
        color = buttonColorsResult.containerColor,
        contentColor = contentColor.copy(alpha = 1f),
        border = border,
        shadowElevation = elevationResult?.shadowElevation ?: 0.dp,
        tonalElevation = elevationResult?.tonalElevation ?: 0.dp,
    ) {
        BoxWithConstraints(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.CenterStart
        ) {
            // Content
            val maxWidth = this.constraints.maxWidth.toFloat()

            when {
                collapsed -> {
                    val animatedProgress = remember { Animatable(initialValue = 0f) }
                    LaunchedEffect(Unit) {
                        animatedProgress.animateTo(
                            targetValue = 1f,
                            animationSpec = tween(600)
                        )
                    }
                    IconButton(
                        onClick = { },
                        modifier = Modifier
                            .scale(animatedProgress.value)
                            .padding(iconPadding)
                            .clip(CircleShape)
                            .background(MaterialTheme.colorScheme.onPrimary)
                            .align(Alignment.Center)
                    ) {
                        Icon(
                            imageVector = Icons.Default.Done,
                            contentDescription = "Done",
                            tint = MaterialTheme.colorScheme.primary
                        )
                    }
                }
                swiped -> {
                    HorizontalDottedProgressBar()
                }
                else -> {
                    dragOffset.value = 0f // 重置为初始状态
                    CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
                        ProvideTextStyle(
                            value = MaterialTheme.typography.bodyMedium
                        ) {
                            Row(
                                Modifier
                                    .fillMaxSize()
                                    .padding(contentPadding),
                                horizontalArrangement = Arrangement.Center,
                                verticalAlignment = Alignment.CenterVertically,
                                content = content
                            )
                        }
                    }
                }
            }
            // Swipe Component
            AnimatedVisibility(visible = !swiped) {
                IconButton(onClick = { }, enabled = enabled, modifier = Modifier
                    .padding(iconPadding)
                    .align(Alignment.CenterStart)
                    .offset { IntOffset(dragOffset.value.roundToInt(), 0) }
                    .draggable(
                        enabled = enabled,
                        orientation = Orientation.Horizontal,
                        state = rememberDraggableState { delta ->
                            val newValue = dragOffset.value + delta
                            dragOffset.value = newValue.coerceIn(0f, maxWidth)
                        },
                        onDragStopped = {
                            if (dragOffset.value > maxWidth * 2 / 3) {
                                dragOffset.value = maxWidth
                                onSwiped.invoke()
                            } else {
                                dragOffset.value = 0f
                            }
                        }
                    )
                    .background(MaterialTheme.colorScheme.onPrimary, shape = CircleShape)
                ) {
                    Icon(
                        imageVector = icon,
                        modifier = Modifier.graphicsLayer {
                            if (rotateIcon) {
                                rotationZ += dragOffset.value / 5
                            }
                        },
                        contentDescription = "Arrow",
                        tint = buttonColorsResult.containerColor,
                    )
                }
            }
        }
    }
}

修复说明

  • 使用ButtonColors.resolve(enabled, interactionSource)获取公开的颜色结果对象,替代直接调用内部的contentColor()和containerColor()方法
  • 使用ButtonElevation.resolve(enabled, interactionSource)获取公开的elevation结果对象,替代直接调用内部的shadowElevation()和tonalElevation()方法
  • 通过remember和derivedStateOf确保状态随enabled和interactionSource变化自动更新

二、BottomSheetDrawer组件修复

问题场景

升级Compose库后,ModalBottomSheetState的isAnimationRunning属性被标记为内部API,直接访问会触发权限错误。

报错信息

Cannot access 'isAnimationRunning': it is internal in 'ModalBottomSheetState'

修复后的代码

@Composable
fun BottomSheetDrawer() {
    val bottomSheetScaffoldState = rememberBottomSheetScaffoldState()
    val coroutineScope = rememberCoroutineScope()
    val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
    BottomSheetScaffold(
        drawerBackgroundColor = MaterialTheme.colorScheme.surface,
        sheetBackgroundColor = MaterialTheme.colorScheme.surface,
        backgroundColor = MaterialTheme.colorScheme.background,
        content = {
            Box {
                ScafoldContent(coroutineScope, bottomSheetScaffoldState, sheetState)
            }
        },
        sheetContent = {
            PlayerBottomSheet()
        },
        drawerContent = {
            DrawerContent()
        },
        scaffoldState = bottomSheetScaffoldState,
        // 替换内部属性isAnimationRunning,通过对比currentValue和targetValue检测动画状态
        sheetPeekHeight = if (sheetState.isVisible || sheetState.currentValue != sheetState.targetValue) 0.dp else 65.dp,
    )
}

修复说明

  • 原内部属性isAnimationRunning用于检测底部抽屉是否处于动画过渡中,可通过对比currentValue和targetValue实现等价逻辑:当两者不一致时,说明组件正在执行动画过渡
  • 保留isVisible判断抽屉已完全展开的场景,结合过渡状态判断,完整复现原逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 14:09:53