Jetpack Compose:如何将列表项包装在卡片中

问题描述 投票:0回答:3

我有一个屏幕,需要在其中显示标题和包含在卡片视图中的项目列表。整个屏幕必须可滚动(如下图所示)。

我知道如何使用可滚动列来做到这一点,但我希望能够使用

LazyColumn
(因为由于视图的复杂性,每个列表项都有自己的 ViewModel,我认为 LazyColumn 会更节省资源) )。对于标题,我可以使用
item
,对于列表,我可以使用
items
。下面是我尝试过的代码:

@Composable
fun Screen(
  items: List<String>
) {
  Column(
    Modifier.fillMaxSize()
  ) {
    TopAppBar(title = { Text(text = "My Activity") })

    LazyColumn {

      // Header
      item {
        Text("Title", Modifier.padding(32.dp))
      }

      // I cannot use Box in this way here
      Box(Modifier.padding(32.dp)) {
        Card {
          items(items.size) {
            Text("Item $it")
          }
        }
      }
    }
  }
}

该代码的问题是我无法将列表项包装在卡片视图中,因为

Card
不是
LazyListScope
。使用 LazyColumn,如何将列表项包装在卡片中?

android android-jetpack-compose
3个回答
0
投票

作为解决方法,您可以通过绘制自定义形状来模拟 Card。

它看起来像这样:screen_record

sealed class Item
class HeaderItem(...): Item()
class ContentItem(...) : Item()

...

val items: SnapshotStateList<Item> = mutableStateListOf()

...

LazyColumn(
        modifier = Modifier.fillMaxSize(),
    ) {
        itemsIndexed(
            items = state.items,
        ) { index, item ->

            val prevItem = state.items.getOrNull(index - 1)
            val nextItem = state.items.getOrNull(index + 1)

            Column {
                when (item) {
                    is HeaderItem -> Header(item)

                    is ContentItem -> {
                        Box(
                            modifier = Modifier
                                .heightIn(min = 48.dp)
                                .fillMaxWidth()
                                .clip(shape = getShape(prevItem, nextItem, 16.dp))
                                .background(Color.Green.copy(0.3F))
                        ) {
                            Item(item)
                        }
                    }
                }
            }
        }
fun getShape(prevItem: Item?, nextItem: Item?, corner: Dp): Shape {
    return if (prevItem is ContentItem && nextItem is ContentItem) {
        //FLAT
        RectangleShape
    } else if (prevItem !is ContentItem && nextItem !is ContentItem) {
        //ROUNDED_ALL
        RoundedCornerShape(corner)
    } else if (prevItem !is ContentItem) {
        //ROUNDED_TOP
        RoundedCornerShape(topStart = corner, topEnd = corner)
    } else {
        //ROUNDED_BOTTOM
        RoundedCornerShape(bottomStart = corner, bottomEnd = corner)
    }
}

0
投票

我正在寻找相同的内容,但不幸的是找不到解决方案,因此按照 @JanBína 在另一个类似问题下的建议我已经自定义了每个项目卡并获得了所需的输出,代码如下所示

@Composable
fun TransactionItem(
    transaction: Transaction,
    index: Int = 0,
    totalSize: Int = 1,
    onTransactionClicked: (Transaction) -> Unit
) {
    val transactionDateTime = Instant.fromEpochMilliseconds(transaction.date).toLocalDateTime(
        TimeZone.currentSystemDefault()
    )
    val cardMod = Modifier
        .padding(horizontal = 5.dp)
        .padding(bottom = if (index == totalSize - 1) 5.dp else 0.dp)
        .fillMaxWidth()
        .padding(horizontal = 5.dp)

    if (totalSize == 1) {
        cardMod.padding(vertical = 5.dp)
    } else when (index) {
        0 -> cardMod.padding(top = 5.dp)
        totalSize - 1 -> cardMod.padding(bottom = 10.dp)
        else -> cardMod.padding(vertical = 0.dp)
    }

    ElevatedCard(
        onClick = {
            onTransactionClicked(transaction)
        },
        modifier = cardMod,
        shape = when (totalSize) {
            1 -> RoundedCornerShape(15.dp)
            else -> when (index) {
                0 -> RoundedCornerShape(topStart = 15.dp, topEnd = 15.dp)
                totalSize - 1 -> RoundedCornerShape(bottomStart = 15.dp, bottomEnd = 15.dp)
                else -> RoundedCornerShape(0)
            }
        }
    ) {
       ///Item Content goes here
    }
}

这不是最终的解决方案,我仍在寻找一个可以使用单张卡实现相同效果的解决方案,最终结果如下


-1
投票

你有点混淆了,你应该把

Card
放在
items
调用中:

    LazyColumn {
      // Header
      item {
        Text("Title", Modifier.padding(32.dp))
      }
      
      items(items.size) {
          // You can use Box in this way here
          Box(Modifier.padding(32.dp)) {
            Card {
              Text("Item $it")
            }
          }
       }
    }
© www.soinside.com 2019 - 2024. All rights reserved.