首页 > 解决方案 > 如何在 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(),
      ),
    );
  }
}

我真的很感激任何建议。

标签: flutterblocflutter-testflutter-bloc

解决方案


推荐阅读