具有ChangeNotifier +提供程序的SearchDelegate

时间:2019-08-23 00:52:45

标签: flutter

如何将ChangeNotifierSearchDelegate一起正确使用?

我有类似这样的东西:

class SearchNotifier with ChangeNotifier {
  List<String> results;


  Future<void> search(String query) async {
    results = await API.search(query);
    notifyListeners();
  }
}

在我的SearchDelegate中:

Widget buildSuggestions(BuildContext context) {
  final searchNotifier = Provider.of<SearchNotifier>(context);
  searchNotifier.search(query);
  ...
}

结果更新时,SearchNotifier更新其侦听器,重建SearchDelegate,调用buildSuggestions,并再次调用search,进入循环。

有没有一种在构建方法之外进行searchNotifier.search(query)的方法?也许我可以通过某种方式将监听器添加到SearchDelegate _queryTextController

我正在使用提供程序注入我的SearchNotifier,因此无论在哪里调用search,我们都需要访问上下文。

3 个答案:

答案 0 :(得分:1)

我通过直接从search方法返回搜索结果,然后使用FutureBuilder来解决了这个问题。

class SearchNotifier with ChangeNotifier {
  Future<List<String>> search(String query) async {
    return await API.search(query);
  }
}

Widget buildSuggestions(BuildContext context) {
  final searchNotifier = Provider.of<SearchNotifier>(context);
  results = searchNotifier.search(query);
  // FutureBuilder on results
  ...
}

SearchNotifier不再是ChangeNotifier,因为问题的根源是notifyListeners

答案 1 :(得分:0)

如果您想使用它TextEditingController来在输入新内容(完全有意义)时开始一个新查询,则可以将以下内容添加到小部件的initState中(假设您在这里使用有状态小部件。

@override
void initState() {
   final searchNotifier = Provider.of<SearchNotifier>(context);
   _myTextEditingController.addListener(() => searchNotifier.search(_myTextEditingController.text));
}

并且不要忘记从build()方法中将其删除。

答案 2 :(得分:0)

我做了不同的选择,但我也在我的应用程序中使用了提供程序。所以我的自定义搜索委托看起来像这样:

 class ExerciseSearchDelegate extends SearchDelegate {
  @override
  List<Widget> buildActions(BuildContext context) {
    return [
      IconButton(
        icon: Icon(Icons.clear),
        onPressed: () {
          query = '';
        },
      ),
    ];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      icon: Icon(Icons.arrow_back),
      onPressed: () {
        close(context, null);
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    // ExeciseList is a widget which accepts a query as optional parameter
    return ExerciseList(
      query: query,
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return Column();
  }

  @override
  ThemeData appBarTheme(BuildContext context) {
    assert(context != null);
    final ThemeData theme = Theme.of(context);
    assert(theme != null);
    return theme;
  }
}

和我的ExerciseList看起来像这样:

class ExerciseList extends StatelessWidget {
  final String query;
  const ExerciseList({this.query, Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final _model = Provider.of<GlobalModel>(context);

    List<ExerciseModel> _results = query != null
        ? _model.exercises
            .where((ex) => ex.name.toLowerCase().contains(query.toLowerCase()))
            .toList()
        : _model.exercises;

    return ListView.builder(
      itemCount: _results.length,
      itemBuilder: (context, position) {
        var exercise = _results[position];
        return MultiProvider(
          providers: [
            ChangeNotifierProvider.value(notifier: exercise),
          ],
          child: ExerciseListItem(),
        );
      },
    );
  }
}

希望这会有所帮助。如果不清楚,请告诉我。谢谢!

相关问题