Compose笔记(七十三)--滑动折叠AppBar

这一节主要了解一下Compose折叠AppBar,在Compose中实现类似Android原生CollapsingToolbarLayout+AppBarLayout的滑动折叠标题栏效果,官方提供了Scaffold+TopAppBar+NestedScroll Connection标准方案,核心依赖 TopAppBar/LargeTopAppBar、scrollBehavior以及嵌套滚动机制,无需自定义复杂布局,简单总结如下:

API:

LargeTopAppBar:Material3提供的可折叠顶部栏,自带展开/折叠两种形态;

rememberTopAppBarState:核心滚动行为,滚动时标题栏逐渐折叠,完全折叠后固定在顶部;

NestedScrollConnection:连接滚动容器(LazyColumn/Column)与顶部栏,实现联动折叠;

Scaffold:标准页面骨架,自动处理滚动区域与AppBar的嵌套;

栗子:

Kotlin 复制代码
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CollapsingAppBarDemo() {
    val topAppBarState = rememberTopAppBarState()
    val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
        state = topAppBarState,
    )

    Scaffold(
        topBar = {
            LargeTopAppBar(
                title = {
                    Text(
                        text = "折叠标题栏演示",
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                },
                navigationIcon = {
                    IconButton(onClick = { /* 打开侧边栏 */ }) {
                        Icon(Icons.Default.Menu, contentDescription = "菜单")
                    }
                },
                actions = {
                    IconButton(onClick = { /* 搜索功能 */ }) {
                        Icon(Icons.Default.Search, contentDescription = "搜索")
                    }
                },
                scrollBehavior = scrollBehavior
            )
        },
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { innerPadding ->

        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding),

            verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp)
        ) {

            items(50) { index ->
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(horizontal = 16.dp, vertical = 12.dp)
                ) {
                    Text(text = "列表项 $index", style = MaterialTheme.typography.bodyLarge)
                }
            }
        }
    }
}
Kotlin 复制代码
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CollapsingAppBarDemo() {
    val topAppBarState = rememberTopAppBarState()
    val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topAppBarState)

    val collapseProgress = topAppBarState.collapsedFraction
    val titleAlpha by animateFloatAsState(
        targetValue = if (collapseProgress > 0.5f) 1f else 0.7f,
        label = "title_alpha_anim"
    )

    Scaffold(
        topBar = {
            LargeTopAppBar(
                title = {
                    Text(
                        text = "自定义折叠标题栏",
                        modifier = Modifier.alpha(titleAlpha), 
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                        style = MaterialTheme.typography.headlineSmall
                    )
                },
                navigationIcon = {
                    IconButton(onClick = {}) {
                        Icon(Icons.Default.Menu, "导航菜单")
                    }
                },
                actions = {
                    IconButton(onClick = {}) {
                        Icon(Icons.Default.Settings, "设置")
                    }
                },
                scrollBehavior = scrollBehavior,
                colors = TopAppBarDefaults.largeTopAppBarColors(
                    scrolledContainerColor = MaterialTheme.colorScheme.secondaryContainer
                )
            )
        },
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { innerPadding ->
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
                .padding(horizontal = 16.dp),
            verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(12.dp)
        ) {
            items(60) { index ->
                Card(
                    modifier = Modifier.fillMaxSize(),
                    shape = androidx.compose.foundation.shape.RoundedCornerShape(8.dp)
                ) {
                    Box(modifier = Modifier.padding(20.dp)) {
                        Text(text = "折叠列表项 $index", style = MaterialTheme.typography.bodyLarge)
                    }
                }
            }
        }
    }
}

注意:

1 必须绑定scrollBehavior且关联嵌套滚动;

2 滚动容器必须是"可滚动组件";

3 必须使用Scaffold且正确处理innerPadding,如LargeTopAppBar必须放在Scaffold的topBar参数中,内容容器必须应用Scaffold回调的innerPadding;

相关推荐
一木 之林6 小时前
Dify学习笔记 03 · RAG检索增强生成:三代范式、评估与落地(第40-45、55-56集)
笔记·小程序·交互·dify
箓维11 小时前
TCP Socket的进阶实现
网络·笔记·tcp/ip
二哈赛车手11 小时前
新人笔记---hermes定时功能设计,具体讲解以及可优化点
java·人工智能·笔记·spring·ai·typescript
星恒随风13 小时前
Linux网络编程:应用层协议究竟是什么?从网络计算器到TCP Socket抽象基类完整实现
linux·网络·笔记·tcp/ip
智学AI14 小时前
AI博主写作素材管理方法分享:资料归集、笔记关联与文档归档
人工智能·笔记
叼烟扛炮14 小时前
[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战
服务器·开发语言·网络·笔记·学习·langchain
weixin_4481199414 小时前
Datawhale Jev Cookbook 202610 笔记5
笔记
一木 之林15 小时前
Dify学习笔记 04 · 检索底座:Embedding、Rerank与向量数据库(第46-54集)
笔记·学习·embedding·dify
ljt272496066115 小时前
Python笔记(十一)--Numpy(一)
笔记·python·numpy
芯思路15 小时前
STM32开发学习笔记之十【AI部署】
笔记·stm32·学习