美文网首页
Compose仿美团左右列表联动

Compose仿美团左右列表联动

作者: 好多个胖子 | 来源:发表于2024-03-31 14:20 被阅读0次

简介

仿造美团外卖点餐页面,左边是菜品类型,右边是菜品详情,右侧列表滑动,左侧菜品跟随选中对应的菜品,如果要固定头的话 可以开启注释掉的stickyHeader替换item


private const val TAG = "WidgetTabList"

enum class TabState {
    Normal, PreCheck, Check, NextCheck
}

enum class ItemType {
    Head, Content
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun <T, E> WidgetTabList(
    modifier: Modifier = Modifier,
    leftModifier: RowScope.() -> Modifier = { Modifier },
    rightModifier: RowScope.() -> Modifier = { Modifier },
    tabList: List<T>,
    itemList: List<E>,
    findTabIndex: (Int, E) -> Int,
    findItemIndex: (Int, T) -> Int,
    getItemType: (E) -> ItemType,
    tabItemLayout: @Composable LazyItemScope.(T, TabState) -> Unit,
    itemHeadLayout: @Composable LazyItemScope.(E) -> Unit,
    itemContentLayout: @Composable LazyItemScope.(E) -> Unit
) {

    var isUserClick by remember {
        mutableStateOf(false)
    }
    var index by remember {
        mutableIntStateOf(0)
    }

    val listState = rememberLazyListState()
    val tabListState = rememberLazyListState()

    val realIndex by remember(itemList) {
        derivedStateOf() {
            val fvIndex = listState.firstVisibleItemIndex

            val i = if (itemList.isEmpty()) {
                0
            } else if (fvIndex >= itemList.size) {
                findTabIndex(fvIndex, itemList.last())
            } else {
                findTabIndex(fvIndex, itemList[fvIndex])
            }
            Log.d(TAG, "derivedStateOf $fvIndex i = $i")
            i
        }
    }

    LaunchedEffect(key1 = realIndex) {
        Log.d(TAG, "Content: index=$index;realIndex=$realIndex;isUserClick=$isUserClick")
        if (!isUserClick && index != realIndex) {
            index = realIndex
            val fi = tabListState.firstVisibleItemIndex
            val count = tabListState.layoutInfo.visibleItemsInfo.size
            val step = tabListState.layoutInfo.viewportSize.height / 2f
            Log.d(TAG, "Content: fi = $fi count=$count index = $index  tabHeight.value=${step}")
            if (fi + count <= index + 1) {
                tabListState.scrollBy(step)
            } else if (index < fi) {
                tabListState.scrollToItem(index)
            }
        }
        isUserClick = false
    }

    val scope = rememberCoroutineScope()
    Row(modifier = modifier) {
        LazyColumn(
            modifier = leftModifier(),
            state = tabListState,
        ) {
            itemsIndexed(tabList, { i, _ -> i }) { i, item ->
                val tabState = when (i) {
                    index -> TabState.Check
                    index - 1 -> TabState.PreCheck
                    index + 1 -> TabState.NextCheck
                    else -> TabState.Normal
                }
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .clickable {
                                Log.d(TAG, "click tab $i")
                                if (index == i) return@clickable
                                index = i
                                isUserClick = true
                                scope.launch {
                                    val itemIndex = findItemIndex(index, tabList[index])
                                    listState.scrollToItem(itemIndex)
                                }
                        }
                ) {
                    tabItemLayout(item, tabState)
                }
            }
        }

        LazyColumn(modifier = rightModifier(), state = listState) {
            itemList.forEach {
                val type = getItemType(it)
                when (type) {
                    ItemType.Head -> {
//                            stickyHeader {
                        item {
                            itemHeadLayout(it)
                        }
//                            }
                    }

                    ItemType.Content -> {
                        item {
                            itemContentLayout(it)
                        }
                    }
                }
            }
        }
    }
}

相关文章

网友评论

      本文标题:Compose仿美团左右列表联动

      本文链接:https://www.haomeiwen.com/subject/zoxbtjtx.html