如何从 SearchAnchor 手动重建 suggestBuilder?

问题描述 投票:0回答:2

我想使用

SearchAnchor
小部件,但不幸的是,我找不到触发重建的方法。我尝试了很多方法来实现类似于我的图片
suggestionsBuilder
中的清单中所示的内容。但是,它不起作用,因为只有在我输入新文本时小部件才会重建,并且会触发
SearchController

我尝试使用有状态小部件并更改状态,但它不起作用。我还尝试了

ValueListenableBuilder
并尝试手动编辑
SearchController
,这绝对不是有效的解决方案,也不起作用。我什至尝试了 Riverpod Provider,如提供的最小代码片段所示。

这让我发疯。感谢您的帮助! :D

使用 Riverpod 进行重现的最小示例(我使用的是 Flutter 3.16.3):

import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

part 'init_jobs_screen.g.dart';

class InitJobsScreen extends ConsumerWidget {
  const InitJobsScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    //This value i want to display
    int seconds = ref.watch(secondsCounterProvider);

    final SecondsCounter notifier = ref.watch(secondsCounterProvider.notifier);
    if (seconds == 0) {
      callFunctionEverySecond(notifier);
    }
    return Scaffold(
        appBar: AppBar(
          title: const Text('Whats going on here?!'),
        ),
        body: Column(
          children: [
            Text('Here it works as expected $seconds'),

            //Here the provider doesnt work -> It drives me quazy
            SearchAnchor.bar(
                suggestionsBuilder: (context, controller) =>
                    [Text(ref.watch(secondsCounterProvider).toString())]),
          ],
        ));
  }
}

//Provider i want to watch
@riverpod
class SecondsCounter extends _$SecondsCounter {
  @override
  int build() => 0;

  void incrementSeconds() => state++;
}

//increment seconds
void callFunctionEverySecond(SecondsCounter notifier) {
  // Call the function every second
  Timer.periodic(const Duration(seconds: 1), (timer) {
    log('increment Secondscounter');
    notifier.incrementSeconds();
  });
}

我尝试了有状态小部件并更改了状态,但这不起作用,我尝试了 ValueListenableBuilder,我尝试手动编辑 SearchController (这确实不是有效的解决方案,尽管不起作用),我尝试了 Riverpod Provider,就像提供的最小代码片段

flutter dart setstate rebuild
2个回答
2
投票

如果您转到源文件 search_anchor.dart,在第 808 行左右,找到

updateSuggestions()
函数,您将看到 suggestBuilder 是如何触发的:

Future<void> updateSuggestions() async {
    if (searchValue != _controller.text) {
      searchValue = _controller.text;
      final Iterable<Widget> suggestions = await widget.suggestionsBuilder(context, _controller);
      if (mounted) {
        setState(() {
          result = suggestions;
        });
      }
    }
  }

所以改变文本确实是触发 suggestBuilder 的唯一条件。因此,在 Flutter 团队添加诸如 buildWhen 参数之类的内容之前,最好的选择是完全绕过它或重置文本。

每当我需要重建时我都会这样做。这不是最漂亮的解决方案,并且会导致快速闪烁,但却是解决问题的最快答案。

SearchController searchController = SearchController();
...
SearchAnchor(
    searchController: searchController,
    ...
);
...
final query = searchController.text;
searchController.text = '';
searchController.text = query;

0
投票

很明显,目前强制

suggestionsBuilder
重建的唯一方法是更改
SearchController
text
,正如 Benjamin 已经声明的那样。这是一个持续存在的问题,可以在此处进行跟踪。但是,对此有一个更简洁的解决方法 - 在这种情况下更改文本的唯一目的是触发刷新,因此对于用户来说文本不得更改(或至少看起来没有更改)。这就是 Unicode 字符
U+200B
(零宽度空格)派上用场的地方。将此字符添加到搜索字符串不会对用户造成任何明显的差异,但足以触发
updateSuggestions
并重建
suggestionsBuilder

在 Dart 中,该字符可以使用 Unicode 字符串文字表示:

const String _zeroWidthSpace = '\u200B';

现在,该字符可用于修改字符串以引起刷新,而不会给用户带来任何可见差异:

void rebuildSuggestions() {
    final previousText = _searchController.text;
    _searchController.text = '$_zeroWidthSpace$previousText'; // This will trigger updateSuggestions and call `suggestionsBuilder`.
    _searchController.text = previousText;
}
© www.soinside.com 2019 - 2024. All rights reserved.