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

如何实现点击TextField时才显示ListView

实现建议列表仅点击TextField时显示

问题描述

当前建议列表默认显示在屏幕上,希望实现仅点击TextField时才显示该列表。尝试过将ListView放入setState中,也试过添加TextEditingController监听器,但均无效,是否需要用按钮包裹ListView?

解决方案

不需要用按钮包裹ListView,只需添加一个状态变量控制列表的显示/隐藏状态,再绑定TextField的点击事件和焦点变化来切换状态即可。以下是修改后的完整代码:

class MySearchBar extends StatefulWidget {
  const MySearchBar({super.key});

  @override
  State<MySearchBar> createState() => _MySearchBarState();
}

class _MySearchBarState extends State<MySearchBar> {
  final myController = TextEditingController();
  final FocusNode _focusNode = FocusNode(); // 监听TextField焦点变化
  static List<RestaurantProfiles> searchList = mySearchList;

  List<RestaurantProfiles> display_list = List.from(searchList);
  bool _isListVisible = false; // 控制列表显示的状态变量

  // 更新搜索建议列表
  void searchUpdate(String value) {
    setState(() {
      display_list = searchList
          .where((element) => element.restaurantName
              .toLowerCase()
              .contains(value.toLowerCase()))
          .toList();
    });
  }

  @override
  void initState() {
    super.initState();
    // 监听焦点失去事件,点击外部时隐藏列表
    _focusNode.addListener(() {
      if (!_focusNode.hasFocus) {
        setState(() {
          _isListVisible = false;
        });
      }
    });
  }

  @override
  void dispose() {
    myController.dispose();
    _focusNode.dispose(); // 释放焦点资源
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(40),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SizedBox(height: 20),
          TextField(
            focusNode: _focusNode,
            onTap: () {
              setState(() {
                _isListVisible = true; // 点击TextField时显示列表
              });
            },
            onChanged: (value) => searchUpdate(value),
            style: const TextStyle(color: Colors.black),
            decoration: InputDecoration(
              filled: true,
              fillColor: Colors.white,
              isDense: true,
              contentPadding: const EdgeInsets.all(10),
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(30),
                borderSide: BorderSide.none,
              ),
              hintText: "添加餐厅",
              hintStyle: const TextStyle(color: Colors.black26),
              prefixIcon: const Icon(Icons.search),
              prefixIconColor: Colors.black,
            ),
          ),
          const SizedBox(height: 5),
          // 根据_isListVisible决定是否显示列表
          _isListVisible
              ? SizedBox(
                  height: 250,
                  child: display_list.isEmpty
                      ? const Center(
                          child: Text(
                            "哎呀... 没有找到结果!",
                            style: TextStyle(fontSize: 20),
                          ),
                        )
                      : Container(
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(10),
                              color: Colors.white70),
                          child: ListView.builder(
                            itemCount: display_list.length,
                            itemBuilder: (context, index) => ListTile(
                              contentPadding: const EdgeInsets.all(8),
                              title: Text(display_list[index].restaurantName),
                              leading: Image(
                                image: AssetImage(display_list[index].img),
                                fit: BoxFit.cover,
                                height: 50,
                                width: 50,
                              ),
                              trailing: const Icon(Icons.add),
                            ),
                          ),
                        ),
                )
              : const SizedBox.shrink(), // 不显示时返回空容器
        ],
      ),
    );
  }
}

关键修改点说明

  • 添加_isListVisible布尔变量,初始值为false,默认不显示列表。
  • 给TextField绑定onTap事件,点击时将_isListVisible设为true,触发列表显示。
  • 新增FocusNode并添加监听,当TextField失去焦点(点击屏幕其他区域)时,将_isListVisible设为false,自动隐藏列表。
  • 在构建UI时,根据_isListVisible的状态决定渲染列表还是空容器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:20:01