kotlinforandroid
07/08/2022, 2:53 PMkey
and this does sadly not work. I think I know why (the item is not at the same "position" in the composable and thus can't be the same).
Code in thread. Any help is appreciated!kotlinforandroid
07/08/2022, 2:53 PM@JvmInline
value class CheckboxListState(
val items: List<CheckboxListItem> = emptyList(),
)
data class CheckboxListItem(
val text: String,
val checked: Boolean,
)
@Composable
fun CheckboxList(
modifier: Modifier = Modifier,
state: CheckboxListState,
onCheckedChange: (Int, Boolean) -> Unit,
onTextValueChange: (Int, String) -> Unit,
onNewItem: () -> Unit,
) {
val focusManager = LocalFocusManager.current
Column(modifier = modifier) {
state.items.forEachIndexed { index, item ->
key(index) {
CheckboxListItem(
item = item,
onCheckedChange = { onCheckedChange(index, it) },
onTextValueChange = { onTextValueChange(index, it) },
onImeNext = {
focusManager.moveFocus(FocusDirection.Down)
},
imeAction = ImeAction.Next,
)
}
}
// The shadow item is only visible if the last item contains any text.
if (state.items.lastOrNull()?.text?.isNotBlank() == true) {
key(state.items.size) {
CheckboxListItem(
modifier = Modifier.alpha(0.38f),
item = CheckboxListItem("", false),
onCheckedChange = {},
onTextValueChange = {
onNewItem()
},
onImeNext = {},
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CheckboxListItem(
modifier: Modifier = Modifier,
item: CheckboxListItem,
onCheckedChange: (Boolean) -> Unit,
onTextValueChange: (String) -> Unit,
imeAction: ImeAction = ImeAction.Default,
onImeNext: (KeyboardActionScope) -> Unit,
) {
val textStyle = LocalTextStyle.current.copy(
textDecoration = if (item.checked) TextDecoration.LineThrough else TextDecoration.None,
)
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
Box(modifier = Modifier.size(64.dp), contentAlignment = Alignment.Center) {
Icon(Icons.Default.DragIndicator, contentDescription = "Move item icon")
}
Box(modifier = Modifier.size(64.dp), contentAlignment = Alignment.Center) {
Checkbox(checked = item.checked, onCheckedChange = onCheckedChange)
}
TextField(
modifier = Modifier.weight(1f),
value = item.text,
onValueChange = onTextValueChange,
colors = TextFieldDefaults.textFieldColors(
containerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
singleLine = true,
readOnly = item.checked,
keyboardActions = KeyboardActions(onNext = onImeNext),
keyboardOptions = KeyboardOptions(imeAction = imeAction),
textStyle = textStyle,
)
}
}
@Preview
@Composable
internal fun PreviewCheckboxList() {
MaterialTheme {
val items = remember {
mutableStateListOf(
CheckboxListItem("Hello, A!", false),
CheckboxListItem("Hello, B!", true),
CheckboxListItem("Hello, C!", false),
CheckboxListItem("Hello, D!", true),
)
}
CheckboxList(
state = CheckboxListState(items = items),
onCheckedChange = { index, value ->
items[index] = items[index].copy(checked = value)
},
onTextValueChange = { index, value ->
items[index] = items[index].copy(text = value)
},
) {
items.add(CheckboxListItem("", false))
}
}
}
Sean Proctor
07/08/2022, 4:17 PMkotlinforandroid
07/08/2022, 5:17 PMImeAction.Next
to change focus to the next field.Sean Proctor
07/08/2022, 5:37 PMSean Proctor
07/08/2022, 5:39 PMSean Proctor
07/08/2022, 5:42 PM