Проблема с анимацией развертывания/свертывания в LazyColumn Jetpack для Android

Я пытаюсь показать раздел внутри LazyColumnкоторый имеет список строк, которые отображаются горизонтально с использованием LazyRow. Я хотел бы иметь кнопку, которая отображает отображение/скрытие, чтобы я мог отображать минимальный список в этом разделе вместо полного списка. Я хотел бы анимировать часть расширения/свертывания, и в настоящее время расширение при нажатии кнопки работает должным образом, но при сворачивании LazyCloumn прокручивается вверх, что, кажется, выталкивает этот раздел за пределы экрана (как показано на видео ниже). Есть ли способ свернуть, чтобы кнопка по крайней мере была привязана к верхней части, а оставшаяся часть была удалена? Таким образом, пользователь по-прежнему может расширить список, если это необходимо, а не прокручивать вверх, чтобы найти кнопку.

Я пробовал следующее, но ни один из них не работает:

  • С использованием AnimatedVisibility
  • С использованием animate*AsStateнизкоуровневые API
  • Также попытался просто удалить содержимое из списка, позволяя LazyColumn изменить порядок на основе содержимого списка.
      val RandomColor
  get() = Color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))

typealias ClickHandler = (Boolean) -> Unit

@Composable
fun DemoLayout(demoDataList: List<DemoData>, isExpanded: Boolean, clickHandler: ClickHandler) {
  LazyColumn {
    demoDataList.forEachIndexed { index, it ->
      when (it) {
        is DemoData.Header -> item(key = "cell_$index") { HeaderComposable(header = it) }
        is DemoData.BigCard -> item(key = "hero_$index") { BigCardComposable(bigCard = it) }
        is DemoData.Card -> item(key = "banner_$index") { CardComposable(card = it) }
        is DemoData.ExpandableSection -> {
          items(count = 2, key = { indexInner: Int -> "categories_first_half_$index$indexInner" }) { index ->
            Section(
              sectionInfo = it.sectionInfo[index]
            )
          }
          //Comment below and try another approach
          item(key = "first_approach_$index") {
            FirstApproach(
              expandableSection = DemoData.ExpandableSection(
                it.sectionInfo.subList(
                  3,
                  5
                )
              )
            )
          }

          //Second approach
          /*if (isExpanded)
            items(count = 3, key = { indexInner -> "categories_second_half_$index$indexInner" }) { index ->
              Section(
                sectionInfo = it.sectionInfo[index + 2]
              )
            }
          item(key = "button_$index") {
            ShowHideButton(isExpanded, clickHandler)
          }*/
        }
      }
    }
  }
}

@Composable
fun FirstApproach(expandableSection: DemoData.ExpandableSection) {
  var expanded by remember { mutableStateOf(false) }
  val density = LocalDensity.current
  Column {

    AnimatedVisibility(
      visible = expanded,
      enter = slideInVertically() +
        expandVertically(
          // Expand from the top.
          expandFrom = Alignment.Top,
          animationSpec = tween(durationMillis = 350, easing = FastOutLinearInEasing)
        ) + fadeIn(
        // Fade in with the initial alpha of 0.3f.
        initialAlpha = 0.3f
      ),
      exit = slideOutVertically(
        animationSpec = tween(durationMillis = 350, easing = FastOutLinearInEasing)
      ) + shrinkVertically(
        shrinkTowards = Alignment.Bottom,
        animationSpec = tween(durationMillis = 350, easing = FastOutLinearInEasing)
      ) + fadeOut(
        animationSpec = tween(durationMillis = 350, easing = FastOutLinearInEasing),
        targetAlpha = 0f
      )
    ) {
      Column {
        for (i in 0 until expandableSection.sectionInfo.size) {
          HeaderComposable(header = expandableSection.sectionInfo[i].header)
          InfoCardsComposable(expandableSection.sectionInfo[i].infoCard)
          DetailsCardComposable(expandableSection.sectionInfo[i].detailCard)
        }
      }
    }
    Button(
      modifier = Modifier
        .padding(top = 16.dp, start = 16.dp, end = 16.dp)
        .fillMaxWidth(),
      onClick = {
        expanded = !expanded
      }) {
      Text(text = if (expanded) "Hide" else "Show")
    }
  }
}

@Composable
fun HeaderComposable(header: DemoData.Header) {
  Row(
    modifier = Modifier
      .padding(top = 16.dp)
      .fillMaxWidth()
      .height(64.dp),
    verticalAlignment = Alignment.CenterVertically
  ) {
    Text(text = header.title, modifier = Modifier.padding(horizontal = 16.dp))
  }
}

@Composable
fun CardComposable(card: DemoData.Card) {
  Card(
    modifier = Modifier
      .padding(top = 16.dp)
      .size(164.dp),
    backgroundColor = RandomColor
  ) {
    Text(text = card.cardText, modifier = Modifier.padding(horizontal = 16.dp))
  }
}

@Composable
fun BigCardComposable(bigCard: DemoData.BigCard) {
  Card(
    modifier = Modifier
      .padding(top = 16.dp)
      .size(172.dp),
    backgroundColor = RandomColor
  ) {
    Text(text = bigCard.bigCardText, modifier = Modifier.padding(horizontal = 16.dp))
  }
}

@Composable
fun Section(sectionInfo: SectionInfo) {
  Column(
    modifier = Modifier.animateContentSize()
  ) {
    HeaderComposable(header = sectionInfo.header)
    InfoCardsComposable(sectionInfo.infoCard)
    DetailsCardComposable(sectionInfo.detailCard)
  }
}

@Composable
private fun ShowHideButton(isExpanded: Boolean, clickHandler: ClickHandler) {
  Button(
    modifier = Modifier
      .padding(top = 16.dp, start = 16.dp, end = 16.dp)
      .fillMaxWidth(),
    onClick = {
      clickHandler.invoke(
        !isExpanded
      )
    }) {
    Text(text = if (isExpanded) "Hide" else "Show")
  }
}

@Composable
fun DetailsCardComposable(detailCardsList: List<DetailCard>) {
  LazyRow(
    modifier = Modifier.padding(top = 16.dp)
  ) {
    items(detailCardsList) {
      DetailCardComposable(detailCard = it)
    }
  }
}

@Composable
fun InfoCardsComposable(infoCardsList: List<InfoCard>) {
  LazyRow(
    modifier = Modifier.padding(top = 16.dp)
  ) {
    items(infoCardsList) {
      InfoCardComposable(infoCard = it)
    }
  }
}

@Composable
fun InfoCardComposable(infoCard: InfoCard) {
  Card(
    modifier = Modifier
      .size(136.dp),
    backgroundColor = RandomColor
  ) {
    Text(text = infoCard.infoText, modifier = Modifier.padding(horizontal = 16.dp))
  }
}

@Composable
fun DetailCardComposable(detailCard: DetailCard) {
  Card(
    modifier = Modifier
      .size(156.dp),
    backgroundColor = RandomColor
  ) {
    Text(text = detailCard.detailText, modifier = Modifier.padding(horizontal = 16.dp))
  }
} 

Полный код для опробования доступен здесь: https://github.com/DirajHS/ComposeAnimation/tree/master .

Я хотел бы знать, является ли это ожидаемым поведением или я делаю что-то не так? Буду очень признателен за любые предложения по привязке кнопки к верху во время сворачивания.

0 ответов

Другие вопросы по тегам