flutter - 如何在 Flutter 的 showSearch 的 SearchDelegate 中访问 BLoC
问题描述
我想为访问数据和使用 SearchDelegate 分离逻辑。但我无法以干净的方式将 BLoC 中的数据提供给 SearchDelegate。
问题是,我只想在点击 appBar 中的搜索图标时加载数据。并非每次都加载 DashboardScreen。所以我不能简单地将我的 IconButton 小部件包装在 BLoC 屏幕中。
我只想拥有一个独立的 SearchDelegate 以便能够使用我传入的任何数据对其进行测试。是的,我可以为该 BLoC 设置一个存根测试环境,但如果可能的话,我宁愿让它们保持独立。
简单画面:
class DashboardScreen extends StatelessWidget {
const DashboardScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () async {
await showSearch(
context: context,
delegate: SearchListView(
listData: data,
),
);
},
),
],
),
body: null,
);
}
}
集团:
class SearchScreen extends StatefulWidget {
SearchScreen({Key key}) : super(key: key);
@override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
SearchBloc _bloc;
@override
void initState() {
super.initState();
_bloc = SearchBloc(repository: getIt<SearchRepository>());
_bloc.add(LoadSearch());
}
@override
Widget build(BuildContext context) {
return BlocBuilder<SearchBloc, CallsApi<SearchState>>(
cubit: _bloc,
builder: (context, state) {
if (state is ApiSuccess<SearchState>) {
// Just need to pass state.response.data to searchDelegate.
// I cannot return or call Widget inside onPressed in IconButton.
return SizedBox.shrink();
}
},
);
}
}
搜索委托:
class SearchListView extends SearchDelegate<Widget> {
final List<String> listData;
SearchListView({this.listData});
// Change input and hint colors while extending Theme from app.
@override
ThemeData appBarTheme(BuildContext context) {
final theme = Theme.of(context);
return theme.copyWith(
textTheme: theme.textTheme.copyWith(
headline6: theme.textTheme.headline6.copyWith(
color: theme.primaryTextTheme.headline5.color,
),
),
// Extend and reduce color strength by half for hint text.
hintColor: theme.primaryTextTheme.headline5.color.withOpacity(0.5),
);
}
;
// Clear icon at the end of appBar.
@override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
// Navigator icon at the start of appBar.
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
// We do not need this since we show all data at first
// and do filtering in buildSuggestion.
@override
Widget buildResults(BuildContext context) {
return SizedBox.shrink();
}
@override
Widget buildSuggestions(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: Space[8]),
child: ListView.separated(
itemCount: listData.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(listData[index]),
contentPadding: EdgeInsets.symmetric(horizontal: Space[24]),
visualDensity: VisualDensity(vertical: -Space[2]),
onTap: () { },
);
},
separatorBuilder: (context, index) => Divider(),
),
);
}
}
我真的很感激任何建议。