Flutter中使用OpenContainer向SearchPage传递选中数据的问题
解决OpenContainer中SubCategoriesContainerBar向SearchPage传递选中数据的两种方案
方案一:组件回调+外部变量传递
无需额外状态管理库,通过组件间回调和父组件变量传递实现数据共享:
- 在父组件中声明变量存储选中的分类:
String? selectedCategory;
- 给
SubCategoriesContainerBar添加选中回调,触发时传递选中数据并打开容器:
class SubCategoriesContainerBar extends StatelessWidget { final List<String> categories; final VoidCallback openContainer; final ValueChanged<String> onCategorySelected; const SubCategoriesContainerBar({ super.key, required this.categories, required this.openContainer, required this.onCategorySelected, }); @override Widget build(BuildContext context) { return ListView.builder( scrollDirection: Axis.horizontal, itemCount: categories.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { onCategorySelected(categories[index]); openContainer(); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text(categories[index]), ), ); }, ); } }
- 父组件中更新
OpenContainer,在closedBuilder中接收选中数据,openBuilder中传递给SearchPage:
OpenContainer<String>( closedShape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), openShape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), openBuilder: (_, closeContainer) => SearchPage( closeContainer: closeContainer, selectedCategory: selectedCategory, ), onClosed: (res) { print('test'); }, tappable: false, closedBuilder: (_, openContainer) => SubCategoriesContainerBar( categories: categories!, openContainer: openContainer, onCategorySelected: (category) => selectedCategory = category, ), )
SearchPage接收并使用选中数据:
class SearchPage extends StatelessWidget { final VoidCallback closeContainer; final String? selectedCategory; const SearchPage({ super.key, required this.closeContainer, this.selectedCategory, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Search'), actions: [ IconButton( icon: const Icon(Icons.close), onPressed: closeContainer, ), ], ), body: Center( child: Text('Selected Category: ${selectedCategory ?? 'No selection'}'), ), ); } }
方案二:使用Provider状态管理
如果需要跨多个组件共享选中状态,或者项目已使用Provider,可采用这种方式:
- 创建Provider类管理选中状态:
import 'package:flutter/foundation.dart'; class SelectedCategoryProvider extends ChangeNotifier { String? _selectedCategory; String? get selectedCategory => _selectedCategory; void updateSelectedCategory(String category) { _selectedCategory = category; notifyListeners(); } }
- 在应用根节点注册Provider:
void main() { runApp( ChangeNotifierProvider( create: (_) => SelectedCategoryProvider(), child: const MyApp(), ), ); }
- 修改
SubCategoriesContainerBar,选中时更新Provider:
class SubCategoriesContainerBar extends StatelessWidget { final List<String> categories; final VoidCallback openContainer; const SubCategoriesContainerBar({ super.key, required this.categories, required this.openContainer, }); @override Widget build(BuildContext context) { final categoryProvider = Provider.of<SelectedCategoryProvider>(context, listen: false); return ListView.builder( scrollDirection: Axis.horizontal, itemCount: categories.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { categoryProvider.updateSelectedCategory(categories[index]); openContainer(); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text(categories[index]), ), ); }, ); } }
SearchPage中监听Provider获取最新选中数据:
class SearchPage extends StatelessWidget { final VoidCallback closeContainer; const SearchPage({ super.key, required this.closeContainer, }); @override Widget build(BuildContext context) { final selectedCategory = Provider.of<SelectedCategoryProvider>(context).selectedCategory; return Scaffold( appBar: AppBar( title: const Text('Search'), actions: [ IconButton( icon: const Icon(Icons.close), onPressed: closeContainer, ), ], ), body: Center( child: Text('Selected Category: ${selectedCategory ?? 'No selection'}'), ), ); } }
- 父组件的
OpenContainer保持原有代码即可,无需额外变量:
OpenContainer<String>( closedShape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), openShape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), openBuilder: (_, closeContainer) => SearchPage(closeContainer), onClosed: (res) { print('test'); }, tappable: false, closedBuilder: (_, openContainer) => SubCategoriesContainerBar( categories: categories!, openContainer: openContainer, ), )
内容的提问来源于stack exchange,提问作者DolDurma
相关产品推荐
相关产品推荐

