簡體   English   中英

Jetpack Compose LazyRow - 居中所選項目

[英]Jetpack Compose LazyRow - Center selected item

如何計算 LazyRow 中所選項目的 position 並將其用於屏幕上的項目居中? 這些項目將根據其內容具有不同的大小。

如果我使用lazyListState.animateScrollToItem(index) go,則所選項目將位於 LazyRow 的左側。 結果

我想要實現的是讓所選項目像這樣居中預期的

我目前擁有的代碼:

@Composable
fun Test() {
    Column {
        TestRow(listOf("Angola", "Bahrain", "Afghanistan", "Denmark", "Egypt", "El Salvador", "Fiji", "Japan", "Kazakhstan", "Kuwait", "Laos", "Mongolia"))
        TestRow(listOf("Angola", "Bahrain", "Afghanistan"))
    }
}

@OptIn(ExperimentalSnapperApi::class)
@Composable
fun TestRow(items: List<String>) {
    val selectedIndex = remember { mutableStateOf(0) }
    val lazyListState = rememberLazyListState()
    val coroutineScope = rememberCoroutineScope()

    LazyRow(
        modifier = Modifier.fillMaxWidth(),
        state = lazyListState,
        horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally),
        contentPadding = PaddingValues(horizontal = 12.dp),
        flingBehavior = rememberSnapperFlingBehavior(
            lazyListState = lazyListState,
            snapOffsetForItem = SnapOffsets.Start
        )
    ) {
        itemsIndexed(items) { index, item ->
            TestItem(
                content = item,
                isSelected = index == selectedIndex.value,
                onClick = {
                    selectedIndex.value = index
                    coroutineScope.launch {
                        lazyListState.animateScrollToItem(index)
                    }
                }
            )
        }
    }
}

@Composable
fun TestItem(
    content: String,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    Button(
        modifier = Modifier.height(40.dp),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = if (isSelected) Color.Green else Color.Yellow,
            contentColor = Color.Black
        ),
        elevation = null,
        shape = RoundedCornerShape(5.dp),
        contentPadding = PaddingValues(0.dp),
        onClick = onClick
    ) {
        Text(
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
            text = (content).uppercase(),
        )
    }
}

代碼horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)是為了確保 LazyRow 在沒有足夠的項目滾動時將所有項目居中。 包含 3 個項目的示例: 全部居中

我已經嘗試過在類似問題上發布的各種建議,但沒有找到解決方案的運氣。 jetpack-compose-lazylist-可能縮放中心項目如何在 lazycolumn-on-jetpackcompose /jetpack-compose-make-the-first-element-in 中聚焦一個不可見的項目-a-lazyrow-be-aligned-to-the-center-o

我找到了適合我需要的解決方案,因為我不希望導航到選定的項目,而看不到它。

此解決方案無法將屏幕上不可見的項目居中。

coroutineScope.launch {
  val itemInfo = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }
  if (itemInfo != null) {
     val center = lazyListState.layoutInfo.viewportEndOffset / 2
     val childCenter = itemInfo.offset + itemInfo.size / 2
     lazyListState.animateScrollBy((childCenter - center).toFloat())
  } else {
     lazyListState.animateScrollToItem(index)
  }
}

希望噸

改進@Markram 的回答

您可以創建“LazyListState”的擴展:

fun LazyListState.animateScrollAndCentralizeItem(index: Int, scope: CoroutineScope) {
    val itemInfo = this.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }
    scope.launch {
        if (itemInfo != null) {
            val center = this@animateScrollAndCentralizeItem.layoutInfo.viewportEndOffset / 2
            val childCenter = itemInfo.offset + itemInfo.size / 2
            this@animateScrollAndCentralizeItem.animateScrollBy((childCenter - center).toFloat())
        } else {
            this@animateScrollAndCentralizeItem.animateScrollToItem(index)
        }
    }
}

然后直接在您的 Composable 中使用它:

val coroutineScope = rememberCoroutineScope()
coroutineScope.launch {
    listState.animateScrollAndCentralizeItem(index , this)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM