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

如何在Flutter中实现Toolbar内SearchView以筛选ListView

嘿,我来帮你搞定Flutter里给Toolbar加SearchView筛选ListView的需求!下面是一步步的实现方案,都是实际项目里常用的套路~

核心实现思路

我们会用AppBar的actions属性嵌入搜索框,通过StatefulWidget维护搜索状态和过滤后的列表数据,实时响应输入并更新ListView内容。

1. 准备基础结构与状态变量

首先创建一个StatefulWidget,定义必要的状态变量:

  • 原始数据源列表(不会被修改)
  • 过滤后的列表(用于渲染ListView)
  • 搜索输入控制器(监听输入变化)
  • 标记是否处于搜索状态(控制搜索框显示/隐藏)
class SearchableListScreen extends StatefulWidget {
  const SearchableListScreen({super.key});

  @override
  State<SearchableListScreen> createState() => _SearchableListScreenState();
}

class _SearchableListScreenState extends State<SearchableListScreen> {
  // 原始数据源,比如从接口获取的列表
  final List<String> _originalItems = [
    "苹果", "香蕉", "橙子", "葡萄", "西瓜",
    "草莓", "芒果", "菠萝", "猕猴桃", "荔枝"
  ];
  // 过滤后的列表,用于渲染
  late List<String> _filteredItems;
  // 搜索输入控制器
  final TextEditingController _searchController = TextEditingController();
  // 是否处于搜索状态
  bool _isSearching = false;

  @override
  void initState() {
    super.initState();
    // 初始化时过滤列表等于原始列表
    _filteredItems = List.from(_originalItems);
    // 监听搜索输入变化,实时过滤
    _searchController.addListener(_onSearchTextChanged);
  }

  @override
  void dispose() {
    // 页面销毁时释放控制器
    _searchController.dispose();
    super.dispose();
  }
}

2. 实现搜索框的显示逻辑

在build方法里,给AppBar的actions添加搜索图标和搜索框,根据_isSearching切换显示状态:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: _isSearching 
          ? TextField(
              controller: _searchController,
              style: const TextStyle(color: Colors.white),
              decoration: const InputDecoration(
                hintText: "搜索水果...",
                hintStyle: TextStyle(color: Colors.white70),
                border: InputBorder.none,
              ),
              autofocus: true, // 进入搜索状态时自动获取焦点
            )
          : const Text("水果列表"),
      actions: [
        IconButton(
          icon: Icon(_isSearching ? Icons.close : Icons.search),
          onPressed: () {
            setState(() {
              _isSearching = !_isSearching;
              // 如果退出搜索状态,清空输入并恢复列表
              if (!_isSearching) {
                _searchController.clear();
              }
            });
          },
        ),
      ],
    ),
    // 下面是ListView部分,稍后实现
    body: _buildListView(),
  );
}

3. 实现实时过滤逻辑

编写_onSearchTextChanged方法,根据输入的文本过滤原始列表,并更新状态:

void _onSearchTextChanged() {
  final query = _searchController.text.toLowerCase();
  setState(() {
    if (query.isEmpty) {
      // 输入为空时,恢复原始列表
      _filteredItems = List.from(_originalItems);
    } else {
      // 过滤包含搜索关键词的项(不区分大小写)
      _filteredItems = _originalItems
          .where((item) => item.toLowerCase().contains(query))
          .toList();
    }
  });
}

4. 构建可筛选的ListView

最后实现_buildListView方法,用过滤后的列表渲染UI,同时处理空结果的情况:

Widget _buildListView() {
  if (_filteredItems.isEmpty) {
    return const Center(
      child: Text("没有找到匹配的结果"),
    );
  }
  return ListView.builder(
    itemCount: _filteredItems.length,
    itemBuilder: (context, index) {
      return ListTile(
        title: Text(_filteredItems[index]),
        // 这里可以添加列表项的点击逻辑
        onTap: () {
          // do something
        },
      );
    },
  );
}

额外优化点

  • 如果数据源是从网络获取的,可以在initState里请求接口,拿到数据后再初始化_originalItems
  • 可以给搜索框添加防抖(比如延迟500ms再执行过滤),避免频繁调用setState
  • 自定义搜索框的样式,比如添加清除按钮、调整输入框颜色等

这样一套下来,你就能拥有一个带搜索筛选功能的ListView啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:46:50