如何实现点击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
相关产品推荐
相关产品推荐

