【发布时间】:2018-10-17 03:51:17
【问题描述】:
我正在尝试创建一个应用程序来显示搜索结果。我有以下非常简单的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 来跟踪Entrys 的列表。可以通过搜索栏进行新的查询,这可能会返回一个随机长度的数据集。然后通过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 个搜索的混合。但是,当在ListView 的itemBuilder 函数中执行打印语句时,_item 变量似乎正在正确更新,并且无论如何不应该真正混合 2 个不同的搜索结果。是什么导致了这种行为?
这是完整的代码:
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(App());
class App extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => MyWidget(),
},
);
}
}
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]));
})),
],
),
));
}
}
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);
}
}
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',
);
}
【问题讨论】: