How to change CheckBox icons more effectively in jetpack compose

44 Views Asked by At

ok so i have two rows of checkboxes that the user can either press checked or uncheked to each individual column so i came up with this idea of code :

fun HowAmIDoingComponent(
    modifier: Modifier = Modifier,
    selfAssessmentList: List<SelfAssessmentTableInfo>,
    onSelectAnswer: (SelfAssessmentTableInfo) -> Unit
) {
    var checkboxPairsStates by remember {
        mutableStateOf(
            selfAssessmentList.map { Pair(false, false) }
        )
    }
    Column(modifier = modifier.background(WizardTheme.colors.white)) {
        selfAssessmentList.mapIndexed { index, selfAssessment ->
            val pairState = checkboxPairsStates[index]
            Row(
                modifier = modifier
                    .fillMaxWidth()
                    .height(IntrinsicSize.Min)
                    .padding(vertical = dimensionResource(id = R.dimen.smallest_margin))
            ) {
                Column(
                    modifier = Modifier
                        .weight(4f)
                        .align(Alignment.CenterVertically)
                ) {
                    BodyTextComponent(text = selfAssessment.title ?: Empty())
                }
                Box(
                    modifier = Modifier
                        .weight(1.5f)
                        .fillMaxHeight(),
                    contentAlignment = Alignment.Center
                ) {
                    CustomCheckbox(
                        iconVectorPositive = ImageVector.vectorResource(id = R.drawable.ic_checked),
                        iconVectorNegative = ImageVector.vectorResource(id = R.drawable.ic_rectangle),
                        checked = pairState.first,
                        onCheckedChange = { isChecked ->
                            onSelectAnswer(selfAssessment)
                            checkboxPairsStates = checkboxPairsStates.toMutableList().apply {
                                set(index, Pair(isChecked, false))
                            }
                        },

                        modifier = Modifier
                            .padding(8.dp)
                            .size(30.dp)
                    )
                }
                Box(
                    modifier = Modifier
                        .weight(1.5f)
                        .fillMaxHeight(),
                    contentAlignment = Alignment.Center
                ) {
                    CustomCheckbox(
                        iconVectorPositive = ImageVector.vectorResource(id = R.drawable.ic_option_no),
                        iconVectorNegative = ImageVector.vectorResource(id = R.drawable.ic_rectangle),
                        checked = pairState.second,
                        onCheckedChange = { isChecked ->
                            onSelectAnswer(selfAssessment)
                            checkboxPairsStates = checkboxPairsStates.toMutableList().apply {
                                set(index, Pair(false, isChecked))
                            }
                        },
                        modifier = Modifier
                            .padding(8.dp)
                            .size(30.dp)
                    )
                }
                MediumSpacer()
            }
            Divider(
                color = WizardTheme.colors.greyLightest,
                thickness = dimensionResource(id = R.dimen.border_stroke)
            )
        }
    }
}

@Composable
fun CustomCheckbox(
    iconVectorPositive: ImageVector,
    iconVectorNegative: ImageVector,
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier
) {
    val iconVector: ImageVector = if (checked) {
        iconVectorPositive
    } else {
        iconVectorNegative
    }
    Icon(
        imageVector = iconVector,
        contentDescription = stringResource(R.string.custom_checkbox),
        tint = Color.Unspecified,
        modifier = modifier.clickable { onCheckedChange(!checked) }
    )
}

this works nicely.... all i do in my viewModel is manage that specificObject he clicked and put it in a list to be sent to the back end and saved as a valid answer.

But for some reason this approach is somehow "slow" and is compromising some slower devices. If i use an android 12 with a slower phone , my checkboxes TICKS dont register unless i change the state of the screen like getting out and back in to the app or pressing something else that doenst involve checkboxes and then they all show up as ticked as they should.

If i use a faster phone i dont get that error at all everything works fine..

So as a " new " compose developer, what exactly am i doing wrong here ? and what could be improved ?

This is what i achieved with this approach : enter image description here

2

There are 2 best solutions below

0
Victor Pierre On BEST ANSWER

Ok so apparently the fact taht i was using A VECTOR instead of a painterResource was really overloading low end devices.

so this was the approach i went with =

   @Composable
fun CustomCheckbox(
    iconResIdPositive: Int,
    iconResIdNegative: Int,
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier
) {
    val iconResId: Int = if (checked) {
        iconResIdPositive
    } else {
        iconResIdNegative
    }
    val painter = painterResource(id = iconResId)
    Image(
        painter = painter,
        contentDescription = stringResource(R.string.custom_checkbox),
        modifier = modifier.clickable { onCheckedChange(!checked) }
    )
}

this solved my issue of checkBox not being ticked :D

1
william xyz On

At a first glance at your sample code I don't see anything related to the checkbox that could be causing performance issues, except for your checkboxPairsStates list update workaround, it's recommended using mutableStateListOf that automatically handles recomposition. Try using this instead:

var checkboxPairsStates = remember {
    mutableStateListOf(
        selfAssessmentList.map { Pair(false, false) }
    )
}