我正在尝试创建一个应用程序以显示搜索结果。我有以下非常简单的StatefulWidget
。它只有一个状态变量data
,该变量在构造函数中传递。
class Entry extends StatefulWidget {
Entry({Key key, @required this.data}) : super(key: key);
final String data;
@override
_EntryState createState() => _EntryState(data);
}
class _EntryState extends State<Entry> {
_EntryState(this.data) : super();
final String data;
@override
Widget build(BuildContext context) {
return Text(data);
}
}
要生成随机长度(0-9之间)的数据集,我使用以下辅助函数,该函数基本上跟踪DateTime
和传递给它的字符串:
List<String> render(String searchTerm) {
final Random rng = new Random();
final String date = DateTime.now().toString();
return List<String>.generate(
rng.nextInt(10),
(int i) => '$searchTerm $i $date',
);
}
最后,我的主要小部件就是这样。它使用状态变量_items
来跟踪Entry
的列表。可以通过搜索栏进行新的查询,它可以返回随机长度的数据集。然后通过ListView
显示该列表。
class MyWidget extends StatefulWidget {
MyWidget({Key key}) : super(key: key);
final String title = "Demo";
@override
_State createState() => _State();
}
class _State extends State<MyWidget> {
List<String> _items = [];
Future<Null> getData(String searchTerm) async {
final entriesToAdd = render(searchTerm);
setState(() {
_items = entriesToAdd;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
onSubmitted: getData,
decoration:
InputDecoration(hintText: 'Search', icon: Icon(Icons.search)),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0), child: Entry(data: _items[index]));
})),
],
),
));
}
}
所以我的问题是我希望当我通过按钮进行搜索(即调用getData
)时,显示的列表将使用新查询的结果进行更新,从而完全覆盖旧查询的结果。这不会发生。显示的列表是正确的长度,但是项目通常是各种先前/当前搜索的组合,如以下屏幕截图所示,其中显示了2个搜索的组合。但是,在itemBuilder
的{{1}}函数中执行打印语句时,ListView
变量似乎正在正确更新,并且无论是否应该混合使用两种不同的搜索结果。是什么原因导致这种现象?
这是完整的代码:
_item
答案 0 :(得分:3)
不要缓存小部件!您应该在每次调用build
时重新构建它们。 (如果您担心这种方法效率低下,请不要这样做。这是Flutter进行设计和优化的方式,以支持此方法。)只需保留字符串列表,然后每次都重新构建Text。
避免只使用静态函数的类。这些可以替换为顶级功能。
尝试以下方法:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => const MyWidget(),
},
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({Key key}) : super(key: key);
@override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
List<String> _items = <String>[];
void getData(String searchTerm) {
final List<String> newEntries = helper(searchTerm);
setState(() {
_items = newEntries;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
onSubmitted: getData,
decoration: const InputDecoration(
hintText: 'Search',
icon: Icon(Icons.search),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) => Container(
padding: const EdgeInsets.all(8.0),
child: Text(_items[index]),
),
),
),
],
),
),
);
}
}
List<String> helper(String searchTerm) {
final Random rng = new Random();
final String date = DateTime.now().toString();
return List<String>.generate(
rng.nextInt(10),
(int i) => '$searchTerm $i $date',
);
}
以下是说明使用StatefulWidget
的版本:
class MyWidget extends StatefulWidget {
const MyWidget({Key key}) : super(key: key);
@override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
List<String> _items = <String>[];
void getData(String searchTerm) {
final List<String> newEntries = helper(searchTerm);
setState(() {
_items = newEntries;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
onSubmitted: getData,
decoration: const InputDecoration(
hintText: 'Search',
icon: Icon(Icons.search),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) => Container(
padding: const EdgeInsets.all(8.0),
child: Entry(data: _items[index]),
),
),
),
],
),
),
);
}
}
class Entry extends StatefulWidget {
const Entry({Key key, @required this.data}) : super(key: key);
final String data;
@override
_EntryState createState() => _EntryState();
}
class _EntryState extends State<Entry> {
bool bold = true;
@override
Widget build(BuildContext context) => GestureDetector(
onTap: () {
setState(() {
bold = !bold;
});
},
child: Text(
widget.data,
style: TextStyle(
fontWeight: bold ? FontWeight.bold : FontWeight.normal,
),
),
);
}