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

Flutter中如何让SearchBar下方显示建议列表?

问题描述

我想要实现Flutter官方SearchBar示例中的效果,让建议列表显示在SearchBar下方(建议项出现在搜索框正下方),但使用示例代码后,点击SearchBar时搜索框和列表会全屏展示。我的代码如下:

@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(
        title: const Text('Add game'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            SearchAnchor(
              builder: (BuildContext context, SearchController controller) {
                return SearchBar(
                  controller: controller,
                  padding: const MaterialStatePropertyAll<EdgeInsets>(
                    EdgeInsets.symmetric(horizontal: 16.0),
                  ),
                  onTap: () {
                    controller.openView();
                  },
                  onChanged: (value) {
                    setState(() {
                      // Update the searchText and button enabled state.
                      searchText = value;
                      isButtonEnabled = searchText.isNotEmpty;
                    });
                    controller.openView();
                  },
                  leading: const Icon(Icons.search),
                );
              },
              suggestionsBuilder:
                  (BuildContext context, SearchController controller) {
                return List<ListTile>.generate(5, (int index) {
                  final String item = 'item $index';
                  return ListTile(
                    title: Text(item),
                    onTap: () {
                      setState(() {
                        controller.closeView(item);
                      });
                    },
                  );
                });
              },
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: isButtonEnabled ? () => onAddToWatchlistClicked() : null,
              style: ElevatedButton.styleFrom(
                backgroundColor: lightColorScheme.primary
              ),
              child: const Text('Add to watchlist'),
            ),
          ],
        ),
      ),
    );
}

我尝试移除其他子组件,仅保留SearchAnchor也无效,请问我遗漏了什么?


解决方案

问题出在SearchAnchor的默认行为:当它放置在Scaffold的body区域时,默认会触发全屏的搜索视图。要实现官方示例中搜索框下方弹出建议列表的效果,有两种简洁的解决方式:

方式一:使用SearchAnchor.bar构造函数(推荐)

这个构造函数专门设计用于生成下拉式的建议框,无需手动定位,直接贴合需求:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Add game'),
      leading: IconButton(
        icon: const Icon(Icons.arrow_back),
        onPressed: () => Navigator.pop(context),
      ),
    ),
    body: Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          SearchAnchor.bar(
            barHintText: '搜索',
            controller: SearchController(),
            suggestionsBuilder: (context, controller) {
              return List<ListTile>.generate(5, (index) {
                final String item = 'item $index';
                return ListTile(
                  title: Text(item),
                  onTap: () {
                    setState(() {
                      controller.closeView(item);
                      searchText = item;
                      isButtonEnabled = true;
                    });
                  },
                );
              });
            },
          ),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: isButtonEnabled ? () => onAddToWatchlistClicked() : null,
            style: ElevatedButton.styleFrom(
              backgroundColor: lightColorScheme.primary
            ),
            child: const Text('Add to watchlist'),
          ),
        ],
      ),
    ),
  );
}

方式二:自定义viewBuilder控制弹出层

如果需要更灵活的样式控制,可以通过viewBuilder手动定位建议列表:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Add game'),
      leading: IconButton(
        icon: const Icon(Icons.arrow_back),
        onPressed: () => Navigator.pop(context),
      ),
    ),
    body: Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Builder(
            builder: (context) {
              return SearchAnchor(
                viewBuilder: (context, controller, child) {
                  return Positioned(
                    top: 80, // 根据实际布局调整搜索框下方的距离
                    left: 16,
                    right: 16,
                    child: Material(
                      elevation: 4,
                      borderRadius: BorderRadius.circular(8),
                      child: SizedBox(
                        height: 200,
                        child: ListView.builder(
                          itemCount: 5,
                          itemBuilder: (context, index) {
                            final String item = 'item $index';
                            return ListTile(
                              title: Text(item),
                              onTap: () {
                                setState(() {
                                  controller.closeView(item);
                                  searchText = item;
                                  isButtonEnabled = true;
                                });
                              },
                            );
                          },
                        ),
                      ),
                    ),
                  );
                },
                builder: (BuildContext context, SearchController controller) {
                  return SearchBar(
                    controller: controller,
                    padding: const MaterialStatePropertyAll<EdgeInsets>(
                      EdgeInsets.symmetric(horizontal: 16.0),
                    ),
                    onTap: () => controller.openView(),
                    onChanged: (value) {
                      setState(() {
                        searchText = value;
                        isButtonEnabled = searchText.isNotEmpty;
                      });
                      controller.openView();
                    },
                    leading: const Icon(Icons.search),
                  );
                },
              );
            },
          ),
          const SizedBox(height: 16),
          ElevatedButton(
            onPressed: isButtonEnabled ? () => onAddToWatchlistClicked() : null,
            style: ElevatedButton.styleFrom(
              backgroundColor: lightColorScheme.primary
            ),
            child: const Text('Add to watchlist'),
          ),
        ],
      ),
    ),
  );
}

核心说明

  • SearchAnchor.bar是官方提供的快捷实现,默认生成下拉式建议框,代码更简洁。
  • 自定义viewBuilder时,需要用Builder包裹以获取正确上下文,通过Positioned组件精准控制建议列表的位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:30:59