Jetpack Compose 实战:使用 IconToggleButton 打造精美自定义 Checkbox(支持背景图切换)

下面是一个完整的实现方案,使用 IconToggleButton 来创建自定义样式的 Checkbox,并支持修改背景图片:

1. 基础实现(带背景图)

@Composable
fun CustomImageCheckbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    checkedImage: Painter,
    uncheckedImage: Painter,
    contentDescription: String? = null,
    enabled: Boolean = true
) {
    IconToggleButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        modifier = modifier,
        enabled = enabled
    ) {
        if (checked) {
            Image(
                painter = checkedImage,
                contentDescription = contentDescription ?: "Checked"
            )
        } else {
            Image(
                painter = uncheckedImage,
                contentDescription = contentDescription ?: "Unchecked"
            )
        }
    }
}

// 使用示例
var checked by remember { mutableStateOf(false) }
val checkedImage = painterResource(R.drawable.ic_checkbox_checked) // 选中状态图片
val uncheckedImage = painterResource(R.drawable.ic_checkbox_unchecked) // 未选中状态图片

CustomImageCheckbox(
    checked = checked,
    onCheckedChange = { checked = it },
    checkedImage = checkedImage,
    uncheckedImage = uncheckedImage,
    modifier = Modifier.size(48.dp),
    contentDescription = "自定义复选框"
)

2. 带动画效果的实现

@Composable
fun AnimatedImageCheckbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    checkedImage: Painter,
    uncheckedImage: Painter,
    contentDescription: String? = null,
    enabled: Boolean = true
) {
    val transition = updateTransition(checked, label = "checkboxTransition")
    val alpha by transition.animateFloat(label = "alpha") { isChecked ->
        if (isChecked) 1f else 0.6f
    }
    val scale by transition.animateFloat(label = "scale") { isChecked ->
        if (isChecked) 1.1f else 1f
    }

    IconToggleButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        modifier = modifier.graphicsLayer {
            this.alpha = alpha
            this.scaleX = scale
            this.scaleY = scale
        },
        enabled = enabled
    ) {
        Crossfade(
            targetState = checked,
            label = "checkboxImageTransition"
        ) { isChecked ->
            Box(contentAlignment = Center) {
                if (isChecked) {
                    Image(
                        painter = checkedImage,
                        contentDescription = contentDescription ?: "Checked",
                        modifier = Modifier.fillMaxSize()
                    )
                } else {
                    Image(
                        painter = uncheckedImage,
                        contentDescription = contentDescription ?: "Unchecked",
                        modifier = Modifier.fillMaxSize()
                    )
                }
            }
        }
    }
}

3. 带背景和前景组合的实现

@Composable
fun ComplexImageCheckbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    backgroundImage: Painter,
    checkedIcon: ImageVector,
    uncheckedIcon: ImageVector,
    checkedTint: Color = Color.White,
    uncheckedTint: Color = Color.Gray,
    contentDescription: String? = null,
    enabled: Boolean = true
) {
    IconToggleButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        modifier = modifier,
        enabled = enabled
    ) {
        Box {
            Image(
                painter = backgroundImage,
                contentDescription = null,
                modifier = Modifier.fillMaxSize(),
                contentScale = ContentScale.Crop
            )
            
            Icon(
                imageVector = if (checked) checkedIcon else uncheckedIcon,
                contentDescription = contentDescription,
                tint = if (checked) checkedTint else uncheckedTint,
                modifier = Modifier
                    .align(Center)
                    .size(24.dp)
            )
        }
    }
}

// 使用示例
var checked by remember { mutableStateOf(false) }
val backgroundImage = painterResource(R.drawable.checkbox_bg) // 背景图片
val checkedIcon = Icons.Filled.Check
val uncheckedIcon = Icons.Filled.Close

ComplexImageCheckbox(
    checked = checked,
    onCheckedChange = { checked = it },
    backgroundImage = backgroundImage,
    checkedIcon = checkedIcon,
    uncheckedIcon = uncheckedIcon,
    modifier = Modifier.size(64.dp),
    contentDescription = "复合样式复选框"
)

4. 带状态指示器的实现

@Composable
fun StatefulImageCheckbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    image: Painter,
    checkedOverlay: @Composable BoxScope.() -> Unit,
    uncheckedOverlay: @Composable BoxScope.() -> Unit = {},
    contentDescription: String? = null,
    enabled: Boolean = true
) {
    IconToggleButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        modifier = modifier,
        enabled = enabled
    ) {
        Box {
            Image(
                painter = image,
                contentDescription = contentDescription,
                modifier = Modifier.fillMaxSize(),
                contentScale = ContentScale.Crop
            )
            
            if (checked) {
                checkedOverlay()
            } else {
                uncheckedOverlay()
            }
        }
    }
}

// 使用示例
var checked by remember { mutableStateOf(false) }
val image = painterResource(R.drawable.profile_image) // 用户头像作为背景

StatefulImageCheckbox(
    checked = checked,
    onCheckedChange = { checked = it },
    image = image,
    modifier = Modifier.size(72.dp),
    checkedOverlay = {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black.copy(alpha = 0.5f))
        ) {
            Icon(
                imageVector = Icons.Default.Check,
                contentDescription = "Selected",
                tint = Color.White,
                modifier = Modifier
                    .align(Center)
                    .size(32.dp)
            )
        }
    },
    contentDescription = "用户选择状态"
)

5. 最佳实践建议

  1. 图片资源准备

    • 为不同状态准备高质量的图片资源
    • 考虑为不同屏幕密度提供多套资源
  2. 可访问性

    // 始终提供内容描述
    contentDescription = if (checked) "已选中" else "未选中"
    
  3. 主题集成

    // 使用主题颜色
    val checkedTint = MaterialTheme.colorScheme.primary
    val uncheckedTint = MaterialTheme.colorScheme.outline
    
  4. 性能优化

    // 对于静态资源使用 remember
    val checkedImage = remember { painterResource(R.drawable.checked) }
    
  5. 响应式设计

    // 根据屏幕大小调整尺寸
    val checkboxSize = if (LocalConfiguration.current.screenWidthDp < 360) 40.dp else 48.dp
    

这些实现方案提供了从简单到复杂的各种自定义选项,你可以根据具体需求选择合适的实现方式。对于大多数应用场景,基础实现或带动画效果的实现已经足够,而对于更复杂的需求,状态指示器实现提供了最大的灵活性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值