I explore about Jetpack Compose, and create a simple PIN Indicator composable view. I add AnimatedContent
to switch between two composable: Text & Box Layout.
However, i found strange transition from Box to Text like image below (there is n
char when I delete value):
https://drive.google.com/file/d/15-fYcsiLsody5LBjTOFy6lHdkCQItl-G/view?usp=sharing
My composable snippet is like below:
@Composable
fun AppPin(
modifier: Modifier = Modifier,
maxLength: Int = 4,
values: List<Int> = listOf(),
onInputPin: (Int) -> Unit,
onRemovePin: () -> Unit
) {
val focusRequester = remember {
FocusRequester()
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
var lastInputPin by remember {
mutableStateOf("")
}
Box(
modifier = modifier.height(40.dp),
contentAlignment = Alignment.Center
) {
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(40.dp),
verticalAlignment = Alignment.CenterVertically
) {
for (i in 0..<maxLength) {
AppPinIndicator(values.getOrNull(i))
}
}
BasicTextField(
modifier = Modifier.focusRequester(focusRequester),
value = lastInputPin,
onValueChange = {
lastInputPin = it
if (it.length < values.size) {
onRemovePin()
} else {
onInputPin(it.lastOrNull()?.toString()?.toIntOrNull() ?: 0)
}
},
textStyle = TextStyle(
textAlign = TextAlign.Center,
color = Color.Transparent
),
cursorBrush = SolidColor(Color.Transparent),
visualTransformation = VisualTransformation.None,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Decimal
)
)
}
}
@Composable
fun AppPinIndicator(value: Int? = null) {
AnimatedContent(targetState = value, label = "") {
if (it == null) {
Box(
modifier = Modifier
.size(24.dp)
.background(
color = if (isSystemInDarkTheme()) InputDarkColor else NeutralColor,
shape = CircleShape
)
)
} else {
Text(
modifier = Modifier.width(24.dp),
text = value.toString(),
style = ChateoTheme.typography.headlineLarge
)
}
}
}
How to fix that? Thank you
That n is initial letter of “null” String and it happens because an item is removed from Composition when transition is over. If you add a check on text of String or display it when state is not null such as
Text(
modifier = Modifier.width(24.dp),
text = it.toString(),
)
To observe change during animation state change you can see by adding a log such as
@Composable
fun AppPinIndicator(
index: Int,
value: Int? = null
) {
AnimatedContent(
targetState = value,
label = ""
) {
println("index: $index, State: $it, value: $value")
if (it == null) {
Box(
modifier = Modifier
.size(24.dp)
.background(
color = Color.Gray,
shape = CircleShape
)
)
} else {
Text(
modifier = Modifier.width(24.dp),
text = it.toString(),
)
}
}
}
For instance, if the last item is 9 and you remove last item it will log
I index: 3, State: 9, value: null
I index: 3, State: null, value: null
I index: 3, State: null, value: null
I index: 3, State: null, value: null
I index: 3, State: null, value: null
As you can see value is null but state turns to null later
1