You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:实现LazyColumn滚动内容滑入TopBar的问题

Jetpack Compose LazyColumn内容滑入TopBar的实现方案

问题场景

LazyColumn包含顶部图片区域和卡片列表,需要实现滚动时卡片能滑入TopBar下方的效果,当前滚动时内容被TopBar遮挡,无法达到预期视觉效果。

当前滚动效果
current scrolling result

预期滚动效果
expected scrolling result

全屏参考效果
full screen image

原代码

Scaffold(
    topBar = {
        CenterAlignedTopAppBar(
            modifier = Modifier
                .background(Color.Transparent),
            title = {
                Image(
                    painter = painterResource(id = R.drawable.ic_logo),
                    contentDescription = ""
                )
            },
            navigationIcon = {
                Row(horizontalArrangement = Arrangement.SpaceBetween) {
                    IconButton(
                        onClick = {
                            navController.navigate(Screen.Account.route)
                        }
                    ) {
                        Icon(
                            painterResource(id = R.drawable.ic_settings),
                            "backIcon",
                            tint = Color.White
                        )
                    }

                    IconButton(
                        onClick = {
                            navController.navigate(Screen.Staking.route)
                        }
                    ) {
                        Icon(
                            painterResource(id = R.drawable.ic_staking),
                            "",
                            tint = Color.White
                        )
                    }
                }
            },
            actions = {
                IconButton(
                    onClick = {
                        navController.navigate(Screen.Swap.route)
                    }
                ) {
                    Icon(
                        painterResource(id = R.drawable.ic_swap),
                        "",
                        tint = Color.White
                    )
                }
                IconButton(
                    onClick = {
                        navController.navigate(Screen.Assets.route)
                    }
                ) {
                    Icon(
                        painterResource(id = R.drawable.ic_asserts),
                        "",
                        tint = Color.White
                    )
                }
            },
            colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                containerColor = Color.Transparent
            )
        )
    },
    containerColor = Color(0xFF18192F),
    modifier = Modifier
) { innerPadding -> innerPadding
    SwipeRefresh(
        modifier = Modifier,
        state = swipeRefreshState,
        onRefresh = {
            viewModel.onEvent(HomeEvent.Refresh)
        }
    ) {
        LazyColumn(
            state = lazyListState,
            modifier = Modifier
                .fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(10.dp),
            contentPadding = PaddingValues(bottom = 16.dp)
        ) {

            item(key = "header: 1") {
                Box(
                    modifier = Modifier
                        .fillMaxWidth(),
                    contentAlignment = Alignment.Center
                ) {
                    GifImage(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(350.dp)
                            .align(Alignment.BottomCenter),
                        image = R.drawable.gif_home_edited,
                        contentScale = ContentScale.Crop
                    )


                    Column(modifier = Modifier.align(Alignment.Center)) {
                        var totalAmountUsd = remember {
                            0.0
                        }
                        if (state.error == null && !state.coin.isNullOrEmpty()) {
                            totalAmountUsd =
                                state.coin.sumOf { balance -> balance.balanceUsd ?: 0.0 }
                        }

                        Text(
                            modifier = Modifier
                                .padding(horizontal = 16.dp)
                                .fillMaxWidth(),
                            text = "$${"%.3f".format(totalAmountUsd, Locale.US)}",
                            color = Color.White,
                            textAlign = TextAlign.Center,
                            fontSize = 40.sp,
                            fontFamily = FontFamily(Font(R.font.circularstdbold)),
                            fontWeight = FontWeight.Bold
                        )
                        Spacer(modifier = Modifier.height(4.dp))
                        Text(
                            modifier = Modifier
                                .padding(horizontal = 16.dp)
                                .fillMaxWidth(),
                            text = "TOTAL BALANCE",
                            color = Color(0xFFDFE1F6),
                            textAlign = TextAlign.Center,
                            style = MaterialTheme.typography.labelSmall
                        )
                    }

                    Spacer(
                        Modifier
                            .fillMaxWidth()
                            .height(32.dp)
                            .background(
                                brush = Brush.verticalGradient(
                                    colors = listOf(
                                        Color.Transparent,
                                        Color(0xFF18192E)
                                    )
                                )
                            )
                            .align(Alignment.BottomCenter)
                    )
                    Text(
                        modifier = Modifier
                            .padding(vertical = 12.dp, horizontal = 20.dp)
                            .fillMaxWidth()
                            .align(Alignment.BottomCenter),
                        text = "WALLET",
                        color = Color(0xFFA9ADD9),
                        textAlign = TextAlign.Start,
                        style = MaterialTheme.typography.labelMedium
                    )
                }
            }

            if (state.error == null) {
                itemsIndexed(
                    items = state.coin,
                    key = { index, item -> if (index == 0) index else item.id }
                ) { index, item ->
                    CryptoCard(
                        modifier = Modifier
                            .padding(horizontal = 16.dp),
                        cryptoCardData = item,
                        navController = navController,
                        coinInfo = state.coinInfo,
                        isExpanded = index == expandedCardIndex
                    ) {
                        expandedCardIndex = if (expandedCardIndex == index) {
                            -1
                        } else {
                            index
                        }
                    }
                }
            }
            item {
                AssetsExplorer(navController)
            }
        }
    }
}

解决方案

核心是让LazyColumn延伸到TopBar所在区域,同时保持TopBar透明,具体修改如下:

1. 修正Scaffold内边距处理

原代码中innerPadding -> innerPadding是错误写法,应移除该返回值,让LazyColumn不受TopBar内边距限制:

) { innerPadding ->
    // 直接编写内容,不再返回innerPadding
    SwipeRefresh(...) { ... }
}

2. 调整LazyColumn的contentPadding

将LazyColumn顶部内边距设为0,让内容从屏幕顶端开始布局,滚动时自然滑入TopBar下方:

contentPadding = PaddingValues(top = 0.dp, bottom = 16.dp)

修正后的完整代码

Scaffold(
    topBar = {
        CenterAlignedTopAppBar(
            modifier = Modifier.background(Color.Transparent),
            title = {
                Image(
                    painter = painterResource(id = R.drawable.ic_logo),
                    contentDescription = ""
                )
            },
            navigationIcon = {
                Row(horizontalArrangement = Arrangement.SpaceBetween) {
                    IconButton(
                        onClick = { navController.navigate(Screen.Account.route) }
                    ) {
                        Icon(
                            painterResource(id = R.drawable.ic_settings),
                            "backIcon",
                            tint = Color.White
                        )
                    }

                    IconButton(
                        onClick = { navController.navigate(Screen.Staking.route) }
                    ) {
                        Icon(
                            painterResource(id = R.drawable.ic_staking),
                            "",
                            tint = Color.White
                        )
                    }
                }
            },
            actions = {
                IconButton(
                    onClick = { navController.navigate(Screen.Swap.route) }
                ) {
                    Icon(
                        painterResource(id = R.drawable.ic_swap),
                        "",
                        tint = Color.White
                    )
                }
                IconButton(
                    onClick = { navController.navigate(Screen.Assets.route) }
                ) {
                    Icon(
                        painterResource(id = R.drawable.ic_asserts),
                        "",
                        tint = Color.White
                    )
                }
            },
            colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                containerColor = Color.Transparent
            )
        )
    },
    containerColor = Color(0xFF18192F),
    modifier = Modifier
) { innerPadding ->
    SwipeRefresh(
        modifier = Modifier,
        state = swipeRefreshState,
        onRefresh = { viewModel.onEvent(HomeEvent.Refresh) }
    ) {
        LazyColumn(
            state = lazyListState,
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(10.dp),
            contentPadding = PaddingValues(top = 0.dp, bottom = 16.dp)
        ) {

            item(key = "header: 1") {
                Box(
                    modifier = Modifier.fillMaxWidth(),
                    contentAlignment = Alignment.Center
                ) {
                    GifImage(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(350.dp)
                            .align(Alignment.BottomCenter),
                        image = R.drawable.gif_home_edited,
                        contentScale = ContentScale.Crop
                    )

                    Column(modifier = Modifier.align(Alignment.Center)) {
                        val totalAmountUsd = remember {
                            if (state.error == null && !state.coin.isNullOrEmpty()) {
                                state.coin.sumOf { it.balanceUsd ?: 0.0 }
                            } else 0.0
                        }

                        Text(
                            modifier = Modifier
                                .padding(horizontal = 16.dp)
                                .fillMaxWidth(),
                            text = "$${"%.3f".format(totalAmountUsd, Locale.US)}",
                            color = Color.White,
                            textAlign = TextAlign.Center,
                            fontSize = 40.sp,
                            fontFamily = FontFamily(Font(R.font.circularstdbold)),
                            fontWeight = FontWeight.Bold
                        )
                        Spacer(modifier = Modifier.height(4.dp))
                        Text(
                            modifier = Modifier
                                .padding(horizontal = 16.dp)
                                .fillMaxWidth(),
                            text = "TOTAL BALANCE",
                            color = Color(0xFFDFE1F6),
                            textAlign = TextAlign.Center,
                            style = MaterialTheme.typography.labelSmall
                        )
                    }

                    Spacer(
                        Modifier
                            .fillMaxWidth()
                            .height(32.dp)
                            .background(
                                brush = Brush.verticalGradient(
                                    colors = listOf(Color.Transparent, Color(0xFF18192E))
                                )
                            )
                            .align(Alignment.BottomCenter)
                    )
                    Text(
                        modifier = Modifier
                            .padding(vertical = 12.dp, horizontal = 20.dp)
                            .fillMaxWidth()
                            .align(Alignment.BottomCenter),
                        text = "WALLET",
                        color = Color(0xFFA9ADD9),
                        textAlign = TextAlign.Start,
                        style = MaterialTheme.typography.labelMedium
                    )
                }
            }

            if (state.error == null) {
                itemsIndexed(
                    items = state.coin,
                    key = { index, item -> if (index == 0) index else item.id }
                ) { index, item ->
                    CryptoCard(
                        modifier = Modifier.padding(horizontal = 16.dp),
                        cryptoCardData = item,
                        navController = navController,
                        coinInfo = state.coinInfo,
                        isExpanded = index == expandedCardIndex
                    ) {
                        expandedCardIndex = if (expandedCardIndex == index) -1 else index
                    }
                }
            }
            item {
                AssetsExplorer(navController)
            }
        }
    }
}

说明

  • TopBar保持containerColor = Color.Transparent,确保下方LazyColumn内容可透过显示。
  • LazyColumn顶部内边距设为0,让内容从屏幕顶端布局,滚动时自然滑入TopBar下方。
  • 修正了原代码中innerPadding的错误处理,解除Scaffold内边距对LazyColumn的布局限制。

内容的提问来源于stack exchange,提问作者Slow Poke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:07:07