【问题标题】:How to show animate an item view in LazyColumn on Jetpack Compose Android如何在 Jetpack Compose Android 上的 LazyColumn 中显示动画项目视图
【发布时间】:2021-05-08 19:55:21
【问题描述】:

我在惰性列视图中有一个项目列表。

当我们从列表中删除一项时如何显示动画。

我需要为被删除的视图设置动画。删除操作是通过按视图内的删除图标来完成的。

我尝试使用AnimationVisibility,但它没有按预期工作。

【问题讨论】:

    标签: android android-jetpack-compose


    【解决方案1】:

    Compose 1.1.0 更新:

    现在可以动画项目位置更改,但删除/插入动画仍然不可能,需要通过我解释的方法来实现。

    要动画项目位置更改,您只需通过key = { it.id } 提供列表中的项目键并使用Modifier.animateItemPlacement()

    原答案

    它尚未得到官方支持,但他们正在努力。您可能可以实现它,但以一种 hacky 方式。

    当您的列表更新时,您的可组合项会重新创建,并且它还不支持项目的动画,因此您必须在项目上添加一个布尔变量并在它“删除”时更改值,而不是从列表中删除它.显示更新后的列表后,您可以对要移除的项目进行动画处理,然后在动画结束后更新没有它的列表。

    我没有亲自测试过这种方法,所以它可能无法按预期工作,但这是我能想到的唯一方法,因为惰性列表不支持更新动画。

    【讨论】:

    【解决方案2】:

    实验性添加了动画延迟列表项位置的功能。

    LazyItemScope 中有一个新的修饰符,称为Modifier.animateItemPlacement()

    使用示例:

    var list by remember { mutableStateOf(listOf("A", "B", "C")) }
    LazyColumn {
        item {
            Button(onClick = { list = list.shuffled() }) {
                Text("Shuffle")
            }
        }
        items(list, key = { it }) {
            Text("Item $it", Modifier.animateItemPlacement())
        }
    }
    

    当您通过LazyListScope.itemLazyListScope.items 提供键时,此修饰符将启用项目重新排序动画。除了项目重新排序之外,由排列或对齐更改等事件引起的所有其他位置更改也将被动画化。

    【讨论】:

      【解决方案3】:

      就像 YASAN 所说的那样,我能够使用 AnimatedVisibility 在 LazyColumn 项目上生成“slideOut”+“fadeOut”动画,只需在项目的 DataClass 上添加 isVisible 属性并将项目视图包装在 @987654324 中@可组合。由于该 api 仍处于实验阶段,请小心。

      供您参考,如果您或其他人可能会寻找它,我将把我的 sn-p 放在这里。

      对于LazyColumn

      LazyColumn {
          items(
              items = notes,
              key = { item: Note -> item.id }
          ) { item ->
              AnimatedVisibility(
                  visible = item.isVisible,
                  exit = fadeOut(
                      animationSpec = TweenSpec(200, 200, FastOutLinearInEasing)
                  )
              ) {
                  ItemNote(
                      item
                  ) {
                      notes = changeNoteVisibility(notes, it)
                  }
              }
          }
      }
      

      对于可组合项目

      @ExperimentalAnimationApi
      @ExperimentalMaterialApi
      @Composable
      fun ItemNote(
          note: Note,
          onSwipeNote: (Note) -> Unit
      ) {
          val iconSize = (-68).dp
          val swipeableState = rememberSwipeableState(0)
          val iconPx = with(LocalDensity.current) { iconSize.toPx() }
          val anchors = mapOf(0f to 0, iconPx to 1)
      
          val coroutineScope = rememberCoroutineScope()
      
          Box(
              modifier = Modifier
                  .fillMaxWidth()
                  .height(75.dp)
                  .swipeable(
                      state = swipeableState,
                      anchors = anchors,
                      thresholds = { _, _ -> FractionalThreshold(0.5f) },
                      orientation = Orientation.Horizontal
                  )
                  .background(Color(0xFFDA5D5D))
          ) {
              Box(
                  modifier = Modifier
                      .fillMaxHeight()
                      .align(Alignment.CenterEnd)
                      .padding(end = 10.dp)
              ) {
                  IconButton(
                      modifier = Modifier.align(Alignment.Center),
                      onClick = {
                          Log.d("Note", "Deleted")
                          coroutineScope.launch {
                              onSwipeNote(note)
                          }
                      }
                  ) {
                      Icon(
                          Icons.Default.Delete,
                          contentDescription = "Delete this note",
                          tint = Color.White
                      )
                  }
              }
      
              AnimatedVisibility(
                  visible = note.isVisible,
                  exit = slideOutHorizontally(
                      targetOffsetX = { -it },
                      animationSpec = TweenSpec(200, 0, FastOutLinearInEasing)
                  )
              ) {
                  ConstraintLayout(
                      modifier = Modifier
                          .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
                          .fillMaxHeight()
                          .fillMaxWidth()
                          .background(Color.White)
                  ) {
                      val (titleText, contentText, divider) = createRefs()
      
                      Text(
                          modifier = Modifier.constrainAs(titleText) {
                              top.linkTo(parent.top, margin = 12.dp)
                              start.linkTo(parent.start, margin = 18.dp)
                              end.linkTo(parent.end, margin = 18.dp)
                              width = Dimension.fillToConstraints
                          },
                          text = note.title,
                          fontSize = 16.sp,
                          fontWeight = FontWeight(500),
                          textAlign = TextAlign.Start
                      )
      
                      Text(
                          modifier = Modifier.constrainAs(contentText) {
                              bottom.linkTo(parent.bottom, margin = 12.dp)
                              start.linkTo(parent.start, margin = 18.dp)
                              end.linkTo(parent.end, margin = 18.dp)
                              width = Dimension.fillToConstraints
                          },
                          text = note.content,
                          textAlign = TextAlign.Start
                      )
      
                      Divider(
                          modifier = Modifier.constrainAs(divider) {
                              start.linkTo(parent.start)
                              end.linkTo(parent.end)
                              bottom.linkTo(parent.bottom)
                              width = Dimension.fillToConstraints
                          },
                          thickness = 1.dp,
                          color = Color.DarkGray
                      )
                  }
              }
          }
      }
      

      还有数据类Note

      data class Note(
          var id: Int,
          var title: String = "",
          var content: String = "",
          var isVisible: Boolean = true
      )
      

      【讨论】:

      • 您可能希望为Note 类实现一个DTO 转换器,并将您的isVisible 字段放在那里,而不是放在Note 类本身中。您不希望数据库中有与 UI 相关的字段
      【解决方案4】:

      如果您使用过 RecyclerView 小部件,您就会知道它会自动为项目更改设置动画。 Lazy 布局尚未提供该功能,这意味着项目更改会导致即时“快照”。您可以关注此错误以跟踪此功能的任何更改。

      来源:https://developer.android.com/jetpack/compose/lists#item-animations

      在这里查看状态:https://issuetracker.google.com/issues/150812265

      【讨论】:

        【解决方案5】:

        如果您实施compose 版本 1.1.0-beta03。现在,我们有了一种新的方式来为项目设置动画。

        Working example in this link with swipeToDismiss.

        Also you may have a look on this example posted by Google.

        【讨论】:

          【解决方案6】:

          我只是在玩,但也许这样的事情会在他们建立正确的解决方案时有所帮助。

              @Composable
          fun <T> T.AnimationBox(
              enter: EnterTransition = expandVertically() + fadeIn(),
              exit: ExitTransition = fadeOut() + shrinkVertically(),
              content: @Composable T.() -> Unit
          ) {
              val state = remember {
                  MutableTransitionState(false).apply {
                      // Start the animation immediately.
                      targetState = true
                  }
              }
          
              AnimatedVisibility(
                  visibleState = state,
                  enter = enter,
                  exit = exit
              ) { content() }
          }
          
          
          LazyColumn(
            state = lazyState
          ) {
              item {
                  AnimationBox {
                      Item(text = "TEST1!")
                  }
                  AnimationBox {
                      Item(text = "TEST2!")
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2021-11-30
            • 2022-07-06
            • 2021-11-09
            • 1970-01-01
            • 2022-10-04
            • 2021-12-28
            • 2021-03-11
            • 2021-07-12
            • 2022-11-05
            相关资源
            最近更新 更多