Flutter 是 Google 的移动 App SDK,它用来帮助创建单代码库(几乎) iOS 和 Android 现代移动应用。它是跨平台移动开发领域的后来者,与 React Native 等框架不同,它不使用 JavaScript 而是采用 DART 作为开发语言。
什么是动态内容?
除非 App 很基础并且是为了学习目的而创建的,否则它始终要使用动态数据,比如说屏幕显示内容将随用户操作和/或网络数据的变化而改变。
多数情况下,动态行为是通过更新界面上显示的内容来实现的。Flutter 提示 ListView.builder
,可用于从外部数据源生成动态内容。
使用 ListView.builder(…)
ListView.builder
是一种构建列表的方法,其中的子 Widget 可以按需构建。但是,与返回静态 Widget 不同的是,它会多次调用(基于 itemCount
)一个生成函数,并可在每次调用时返回不同的 Widget。
举个例子,让我们创建一个包含基本 MaterialApp
的简单应用,其中 Scaffold
包含 AppBar
和 Body
。
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext ctxt) {
return new MaterialApp(
home: new ListDisplay(),
);
}
}
class ListDisplay extends StatelessWidget {
@override
Widget build (BuildContext ctxt) {
return new Scaffold(
appBar: new AppBar(title: new Text("Dynamic Demo"),),
body: // ListView.builder() 在这里使用.
),
);
}
}
要使用 ListView.builder
,我们必须使用 new
调用其构造方法来创建它的实例,它需要多个参数,而其中两个特别重要:
- itemCount
- itemBuilder
itemCount
参数决定调用 itemBuilder
中回调函数的次数。
为了证明这一点,假设在我们的应用中有一个这样的全局列表:
List<String> litems = ["1","2","Third","4"];
让我们使用 ListView.builder(...)
来显示 Body
中的列表项,代码如下所示:
body: new ListView.builder
(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int index) {
return new Text(litems[index]);
}
)
这里回调函数被就地调用 4 次,每次调用将生成一个 Text Widget
以显示在 Body
中。
我们也可以编写一个独立的函数设置给 itemBuilder
:
// 从 itemBuilder 调用的独立函数
Widget buildBody(BuildContext ctxt, int index) {
return new Text(litems[index]);
}
(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int index) => buildBody(ctxt, index)
),
这两情况下的输出都应该是这样的:
如果我们只是想在每次应用加载 Widget 时显示不同的内容,可以在无状态(Stateless)Widget 中使用 ListView.Builder(..)
。但如果想动态更新已显示的内容,则可以使用带状态的 Widget 。
带状态 Widget 下的 ListView.builder(…)
让我们先将已有代码转换为有状态的 Widget:
class ListDisplay extends StatefulWidget {
@override
State createState() => new DyanmicList();
}
class DyanmicList extends State<ListDisplay> {
@override
Widget build (BuildContext ctxt) {
return new Scaffold(...)
}
为了正确理解带状态部件中的 ListView.builder(..)
,可以使用带状态 Widget 创建一个非常简单的 ToDo 待办 App。我们将创建文本输入区域(例如 TextField
,允许用户在 ToDo 列表中添加自定义条目),一旦条目添加到 ToDo 列表中,它会被即时显示在屏幕上。
由于我们将在 Body:
中创建多个 Widget,因为必须使用能容纳多个子 Widget 的部件,比如 Column:
。但是 ListView.builder(...)
无法在 Column 下工作,除非它被包装在 Expanded
Widget 内部,Expanded
Widget 允许 Column
元素展开并填充在主轴中,这也是ListView.builder(...)
所需要的。
因此整个继承体系应该像这样:
为了将文本条目加入列表,我们需要一个空列表和 TextEditingController
:
List<String> litems = [];
final TextEditingController eCtrl = new TextEditingController();
下面是 TextField
Widget 如何被创建:
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text); // Append Text to the list
eCtrl.clear(); // Clear the Text area
setState(() {}); // Redraw the Stateful Widget
},
),
ListView.builder(...)
的实现没有任何修改,但它将被包装到 Expanded
Widget 里:
new Expanded(
child: new ListView.builder
(
itemCount: lItems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new Text(lItems[Index]);
}
)
)
我们已经准备好动态更新屏幕内容,这是操作的结果:
下面是 DynamicList
类的完整代码:
class DyanmicList extends State<ListDisplay> {
List<String> litems = [];
final TextEditingController eCtrl = new TextEditingController();
@override
Widget build (BuildContext ctxt) {
return new Scaffold(
appBar: new AppBar(title: new Text("Dynamic Demo"),),
body: new Column(
children: <Widget>[
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
new Expanded(
child: new ListView.builder
(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new Text(litems[Index]);
}
)
)
],
)
);
}
}
这就是所有的内容了,我希望已经解释清楚了如何使用 ListView.builder(...)
来生成动态内容。
感谢你的阅读!
原文: https://medium.com/@DakshHub/flutter-displaying-dynamic-contents-using-listview-builder-f2cedb1a19fb
作者:Daksh
编译:码王爷