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

Jetpack Compose:带scrollBehavior的M3 TopAppBar实现搜索栏切换

解决方案

核心问题是你之前的实现改动了TopAppBar的内部结构,导致scrollBehavior无法和TopAppBar正确绑定。正确的思路是保持TopAppBar实例不变,仅切换它的title区域内容,同时确保滚动行为的关联不中断。

具体实现步骤:

  1. 维护搜索激活状态、搜索文本状态,以及搜索框焦点请求器
var isSearchActive by remember { mutableStateOf(false) }
var searchQuery by remember { mutableStateOf("") }
val focusRequester = remember { FocusRequester() } // 用于切换到搜索模式时自动获取焦点
  1. 初始化enterAlwaysScrollBehavior
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
  1. 在TopAppBar的title中用AnimatedContent切换标题/搜索框
Scaffold(
    topBar = {
        TopAppBar(
            title = {
                AnimatedContent(targetState = isSearchActive, label = "search_toggle") { active ->
                    if (active) {
                        TextField(
                            value = searchQuery,
                            onValueChange = { searchQuery = it },
                            placeholder = { Text("Search cards...") },
                            singleLine = true,
                            modifier = Modifier.focusRequester(focusRequester),
                            colors = TextFieldDefaults.colors(
                                focusedContainerColor = Color.Transparent,
                                unfocusedContainerColor = Color.Transparent,
                                disabledContainerColor = Color.Transparent,
                                focusedIndicatorColor = Color.Transparent,
                                unfocusedIndicatorColor = Color.Transparent
                            )
                        )
                    } else {
                        Text("Cards")
                    }
                }
            },
            actions = {
                IconButton(onClick = { isSearchActive = !isSearchActive }) {
                    Icon(
                        imageVector = if (isSearchActive) Icons.Default.Close else Icons.Default.Search,
                        contentDescription = if (isSearchActive) "关闭搜索" else "打开搜索"
                    )
                }
            },
            scrollBehavior = scrollBehavior // 关键:保持scrollBehavior绑定在当前TopAppBar实例上
        )
    },
    content = { padding ->
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .padding(padding)
                .nestedScroll(scrollBehavior.nestedScrollConnection), // 关键:让LazyColumn和scrollBehavior联动
            contentPadding = PaddingValues(16.dp)
        ) {
            // 示例列表内容
            items(50) { index ->
                Card(
                    modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
                    elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
                ) {
                    Text(text = "Card $index", modifier = Modifier.padding(16.dp))
                }
            }
        }
    }
)

// 切换到搜索模式时自动获取焦点
LaunchedEffect(isSearchActive) {
    if (isSearchActive) {
        focusRequester.requestFocus()
    }
}

关键注意点:

  • 不要替换整个TopAppBar,仅修改title区域内容,确保scrollBehavior始终绑定在同一个TopAppBar实例上。
  • 必须给LazyColumn添加.nestedScroll(scrollBehavior.nestedScrollConnection),否则滚动事件无法传递给TopAppBar触发隐藏/显示逻辑。
  • 若坚持使用Crossfade替代AnimatedContent,逻辑完全一致,仅需把AnimatedContent替换为Crossfade(targetState = isSearchActive)即可。

这样实现后,搜索切换功能和TopAppBar的滚动隐藏/显示特性就能同时正常工作了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:42:15