Анимировать видимость в композиции
У меня есть текст, который нужно анимировать, чтобы показать и скрыть значение null или нет. было бы прямолинейно, если бы обзорность отдельно регулировалась, но это то, что у меня получилось. В приведенном ниже коде анимация ввода работает, но анимация выхода не работает, поскольку текстовое значение равно нулю. Я могу что-то придумать с запоминанием старого значения, но не знаю, как это сделать.
@Composable
fun ShowAnimatedText(
text : String?
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
AnimatedVisibility(
visible = text != null,
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
text?.let {
Text(text = it)
}
}
}
}
3 ответа
Я думаю, что анимация затухания на самом деле работает «сама по себе».
подозреваю параметрtext: String?
это значение, исходящее из поднятого "состояния" где-то наверхуShowAnimatedText
, и поскольку вы непосредственно наблюдаете за ним внутри области анимации , когда вы меняете его на ноль, он мгновенно удаляетText
компонуемый, и вы не наблюдаете медленное затухание.
AnimatedVisibility(
...
) {
text?.let { // your'e directly observing a state over here
Text(text = it)
}
}
Это моя попытка завершить ваш фрагмент, основанный на моем предположении, и заставить его работать, постепенное появление работает, но желаемое постепенное исчезновение происходит мгновенно.
@Composable
fun SomeScreen() {
var text by remember {
mutableStateOf<String?>("Initial Value")
}
Row(
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = {
text = "New Value"
}) {
Text("Set New Value")
}
Button(onClick = {
text = null
}) {
Text("Remove Value")
}
AnimatedText(text = text)
}
}
@Composable
fun ShowAnimatedText(
text : String?
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
AnimatedVisibility(
visible = text != null,
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
text?.let {
Text(text = it)
}
}
}
}
Вы можете решить эту проблему, изменивtext
на значение, не являющееся состоянием, и измените свою логику видимости с использования проверки допустимости значений NULL на некоторую «бизнес-логику», которая потребует, чтобы она былаvisible
илиhidden
, изменив приведенные выше коды следующим образом.
@Composable
fun SomeScreen() {
var show by remember {
mutableStateOf(true)
}
Row(
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = {
show = !show
}) {
Text("Set New Value")
}
AnimatedText(text = "Just A Value", show)
}
}
@Composable
fun ShowAnimatedText(
text : String?,
show: Boolean
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
AnimatedVisibility(
visible = show,
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
text?.let {
Text(text = it)
}
}
}
}
Jetpack ComposeAnimatedContent
API может быть тем, что вам нужно, поскольку вы получаете объект данных, передаваемый в лямбду, и можете проверить его на наличие значений NULL, например:
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun ShowAnimatedText(
text : String?
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
AnimatedContent(
targetState = text,
transitionSpec = {
fadeIn(animationSpec = tween(2000)) with
fadeOut(animationSpec = tween(2000))
}
) { text ->
text?.let {
Text(text = it)
}
}
}
}
- нет никаких сбоев анимации при сокрытии (например, когда значение становится
null
) - это также учитывается родительским макетом (например, одноуровневые представления плавно анимируются, чтобы освободить место).
У меня была та же проблема, мне помог этот ответ: /questions/60840752/kak-ispolzovat-animatedvisibility-s-nulevyimi-znacheniyami/66034277#66034277
Я исправил это, запомнив предыдущее состояние (или не устанавливая нулевое значение), пока не завершится анимация выхода, если текст равен нулю.
Спасибо zab.y ваше предложение.
@Composable
fun ShowAnimatedText(
text : String?,
show: Boolean
) {
var localText by remember {
mutableStateOf<String?>(null)
}
AnimatedContent(show, localText)
LaunchedEffect(key1 = text, block = {
if(text == null){
delay(2000)
}
localText = text
})
}
@Composable
private fun AnimatedContent(show: Boolean, localText: String?) {
Column(
modifier = Modifier.fillMaxWidth()
) {
AnimatedVisibility(
visible = show,
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
localText?.let {
Text(text = it)
}
}
}
}