Flutter 带有ChangeNotifier+提供程序的SearchDelegate

Flutter 带有ChangeNotifier+提供程序的SearchDelegate,flutter,Flutter,如何将ChangeNotifier与SearchDelegate一起正确使用 我有一些东西看起来像这样: class ExerciseSearchDelegate extends SearchDelegate { @override List<Widget> buildActions(BuildContext context) { return [ IconButton( icon: Icon(Icons.clear),

如何将ChangeNotifier与SearchDelegate一起正确使用

我有一些东西看起来像这样:

 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;
  }
}
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(),
        );
      },
    );
  }
}
使用ChangeNotifier类SearchNotifier{ 列出结果; 未来搜索字符串查询异步{ 结果=等待API.searchquery; 通知听众; } } 在我的发言中:

Widget BuildSuggestionBuildContext上下文{ final searchNotifier=Provider.ofcontext; searchNotifier.searchquery; ... } 当结果更新时,SearchNotifier更新其侦听器,SearchDelegate被重建,buildSuggestions被调用,search被再次调用,进入循环

是否有一种在生成方法之外执行searchNotifier.searchquery的方法?也许我可以在SearchDelegate\u queryTextController中添加一个侦听器


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

我做了不同的选择,但我也在我的应用程序中使用提供程序。因此,我的自定义搜索委托如下所示:

 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;
  }
}
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(),
        );
      },
    );
  }
}
我的练习表如下所示:

 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;
  }
}
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(),
        );
      },
    );
  }
}

希望这有帮助。如果有什么不清楚的,请告诉我。谢谢大家!

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

使用ChangeNotifier类SearchNotifier{ 未来搜索字符串查询异步{ 返回等待API.searchquery; } } Widget BuildSuggestionBuildContext上下文{ final searchNotifier=Provider.ofcontext; 结果=searchNotifier.searchquery; //基于结果的未来建设者 ... }
SearchNotifier不再需要是ChangeNotifier,因为问题的根源是notifyListeners。

在此解决方案中,GlobalModel是否在任何步骤中调用notifyListeners?我遇到的问题是,我会在buildSuggestions中调用GlobalModel.search。search调用外部API并最终调用notifyListeners,导致再次调用buildSuggestions,循环将重复。在查看了您的解决方案之后,它给了我一个关于如何修改代码以解决问题的提示。我很快会在这里发布解决方案。单击按钮时会调用showSearch,因此即使由于在某些地方调用了notifyListeners而重新创建了小部件,也不会再次调用showSearch,因此不会调用两次buildSuggestions或buildResults。在我的例子中,notifyListeners是在我用于buildSuggestions和buildResults的小部件中调用的,它可以正常工作。