我想使用
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,就像提供的最小代码片段
如果您转到源文件 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;
很明显,目前强制
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;
}