Переход общего элемента: запуск анимации сброса общего элемента при переходе.Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Переход общего элемента: запуск анимации сброса общего элемента при переходе.

Сообщение Anonymous »

В настоящее время я экспериментирую с переходом общего элемента в Jetpack Compose и столкнулся с проблемой.
Проблема: Запускаемая анимация внутри общего элемента сбрасывается при переходе общего элемента.
Код для воспроизведения:

Код: Выделить всё

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
private fun SharedTransition(modifier: Modifier = Modifier) {
var inLeft by remember { mutableStateOf(true) }

SharedTransitionLayout(modifier) {
AnimatedContent(
modifier = Modifier.clickable { inLeft = !inLeft },
targetState = inLeft
) { targetState ->
if (targetState) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
AnimatedBox(
sharedTransitionScope = this@SharedTransitionLayout,
animatedContentScope = this@AnimatedContent,
)
}
} else {
Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier.fillMaxWidth()
) {
AnimatedBox(
sharedTransitionScope = this@SharedTransitionLayout,
animatedContentScope = this@AnimatedContent,
)
}
}
}
}
}

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
private fun AnimatedBox(
sharedTransitionScope: SharedTransitionScope,
animatedContentScope: AnimatedContentScope,
modifier: Modifier = Modifier
) {
with(sharedTransitionScope) {
val transition = rememberInfiniteTransition()
val color by transition.animateColor(
initialValue = Color.Green,
targetValue = Color.Black,
animationSpec = infiniteRepeatable(
tween(durationMillis = 1500, easing = LinearEasing),
RepeatMode.Reverse,
),
)

Box(
modifier
.size(BoxSize)
.sharedElement(
rememberSharedContentState(key = "animated_box"),
animatedContentScope,
)
.background(color)
)
}
}

private val BoxSize = 48.dp
Это приводит к следующему:
Изображение

Анимация должна медленно плавно переходить от зеленого к черному — вперед и назад. Но когда переход запускается нажатием, анимация переходит к первоначальному ярко-зеленому цвету.
Лучше всего это видно на видео, когда поле находится с правой стороны.
Я ожидал, что анимация не будет перезапущена при переходе.
Я попробовал обернуть анимированный элемент в movableContentOf { , но результат тот же:

Код: Выделить всё

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
private fun MovableContentSharedTransition(modifier: Modifier = Modifier) {
val animatedBox =
remember {
movableContentWithReceiverOf  { animatedContentScope ->
val transition = rememberInfiniteTransition()
val color by transition.animateColor(
initialValue = Color.Magenta,
targetValue = Color.Black,
animationSpec = infiniteRepeatable(
tween(durationMillis = 1500, easing = LinearEasing),
RepeatMode.Reverse,
),
)

Box(
Modifier
.size(48.dp)
.sharedElement(
rememberSharedContentState(key = "animated_box"),
animatedContentScope,
)
.background(color)
)
}
}

var inLeft by remember { mutableStateOf(true) }

SharedTransitionLayout {
AnimatedContent(
modifier = modifier.clickable { inLeft = !inLeft },
targetState = inLeft
) { targetState ->
if (targetState) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, this@AnimatedContent)
}
} else {
Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, this@AnimatedContent)
}
}
}
}
}
Составьте версию спецификации: "androidx.compose:compose-bom:2024.09.02".
Вопрос:< /strong> Есть ли способ сохранить анимацию? Можно ли решить эту проблему с помощью moveableContentOf { ?

Обновить
После ответа фракийцев я поэкспериментировал с еще несколько созвездий.
Работает ли moveableContentOf { с анимацией?

Да . При использовании moveableContentOf { без какого-либо перехода общего элемента анимация не перезапускается:
Изображение

Код: Выделить всё

moveableContentOf { }
, похоже, работает так, как ожидалось: не создается новый Composable при переключении блоков, а повторно используется существующий экземпляр с его состоянием анимации.

Код: Выделить всё

@Composable
private fun MovableContentBox(modifier: Modifier = Modifier) {
val animatedBox =
remember {
movableContentOf {
Box(
Modifier
.size(BoxSize)
.background(rememberInfiniteColorChangeTransition())
)
}
}

var inLeft by remember { mutableStateOf(true) }

Box(
modifier = modifier.clickable { inLeft = !inLeft },
) {
if (inLeft) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
animatedBox()
}
} else {
Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier.fillMaxWidth()
) {
animatedBox()
}
}
}
}
Только AnimatedContent вызывает проблему перезапуска?
Нет.
Только AnimatedContent вызывает проблему перезапуска?

Нет.
Только AnimatedContent вызывает проблему перезапуска? strong> Я попробовал AnimatedVisibility, и это тоже вызывает проблему.

Код: Выделить всё

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
private fun MovableContentAnimatedVisibilitySharedElement(modifier: Modifier = Modifier) {
val animatedBox =
remember {
movableContentWithReceiverOf  { animatedContentScope ->
Box(
Modifier
.size(BoxSize)
.sharedElement(
rememberSharedContentState(key = "animated_box"),
animatedContentScope,
)
.background(rememberInfiniteColorChangeTransition())
)
}
}

var inLeft by remember { mutableStateOf(true) }

SharedTransitionLayout {
Box(
modifier = modifier.clickable { inLeft = !inLeft },
) {
AnimatedVisibility(visible = inLeft) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, this@AnimatedVisibility)
}
}
AnimatedVisibility(visible = !inLeft) {
Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, this@AnimatedVisibility)
}
}
}
}
}
Работает ли .sharedElementWithCallerManagedVisibility() с movableContentOf {}?[/b]
Да:
Изображение

Код: Выделить всё

@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
private fun MovableContentSelfControlledVisibilitySharedTransition(modifier: Modifier = Modifier) {
val animatedBox =
remember {
movableContentWithReceiverOf { isVisible ->
Box(
Modifier
.size(BoxSize)
.sharedElementWithCallerManagedVisibility(
rememberSharedContentState(key = "animated_box"),
isVisible,
)
.background(rememberInfiniteColorChangeTransition())
)
}
}

var inLeft by remember { mutableStateOf(true) }

SharedTransitionLayout {
Box(
modifier = modifier.clickable { inLeft = !inLeft },
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, inLeft)
}

Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier.fillMaxWidth()
) {
animatedBox(this@SharedTransitionLayout, !inLeft)
}
}
}
}
Навигация Android Jetpack
Навигация Android Jetpack NavHost использует AnimatedContent для переходов. Переходы общих элементов между пунктами назначения, вероятно, имеют одну и ту же проблему (не проверял).

Я предполагаю, что причина следующая: Composable анимированного блока с moveableContentOf { фактически добавляется в иерархию дважды одновременно. Таким образом, его нельзя переместить, и его состояние нельзя передать другим.
Решения на данный момент:
  • Использовать AnimatedContent / AnimatedVisibility и поднимите состояние анимации (ответ Thracian).

    Состояние анимации должно быть перемещено за пределы общего элемента (поднято или нет). ) и разделяется между двумя компонентами Composable. Возможно, это невозможно/нежелательно.
[*]Используйте moveableContentOf { и .sharedElementWithCallerManagedVisibility()
  • Невозможно, если AnimatedVisibilityScope предоставляется от другой стороны (NavHost).


Полный код: https://github.com/aruh/shared-element- ... set-sample< /п>

Подробнее здесь: https://stackoverflow.com/questions/790 ... on-transit
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»