会介绍 StatefulWidget 与 StatelessWidget 的不同以及 StatefulWidget 是如何工作的。如果已经查看我们之前的分享,想必大家对 StatelessWidget 应该有了一定的了解和认识。不过 StatelessWidget 中的数据是需要从外层传入的,随后固定不变了,当数据改变了 StatelessWidget 也不会随之重新渲染界面进行改变。为了解决这个问题就出现了 StatefulWidget。在 StatefulWidget 中会有 state 对象根据数据改变重新触发 Widget 构建来实现重新渲染界面。
在下面代码中我们需要 _tut 是可以随时间改变的。不过 StatefulWidget 是由 Widget 和 state 对象两部分组成的。Widget 负责做两件事持有不可变的变量例如 startingTut 和一个 state。
有关他们是如何工作我们可以看一看下图,Widget Tree 和 Element Tree
- 根据 Widget Flutter 来创建 Element 然后就返回 StatefulElement.
StatefulWidget 也会对应一个 StatefulElement,StatefulWidget 作为 StatefulElement 的蓝图,StatefulElement 是对应屏幕上用户看到组件。
class TutManager extends StatefulWidget {
final String startingTut;
TutManager({this.startingTut = 'default tut'});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TutManagerState();
}
}
接下来 StatefulElement 反过来会要求 StatefulWidget 创建一个状态,这时候就会调用 createState() 方法来创建一个状态。
在 state 中维护着变量 _tuts,和一个 StatelessWidget
以为 state 对象持有一个 widget 的引用,该 Widget 具有状态。
现在我们所有内容已经建立好关系,也渲染到界面上,现在我们通过 setState 方法来更改状态
onPressed: () {
setState(() {
_tuts.add("Dart");
});
},
当我们调用 setState 方法更改 state 中 tuts 的值,这样 _TutManager 就会将 _tuts 标记为脏数据,在以下帧渲染时候会将最新的数据更新到界面上。Tuts Widget 将会被新的 Tuts 所替换。
statefulWidget 还有一个好处就是即使我们 startTut 值发生改变从而产生了新的 StatefulWidget 只要其他不发生改变,最会只改变这个节点然后进行替换并不会重新生成结构。
@override
void didUpdateWidget(HomeScreenTopPart oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
}
如果 state 对象需要知道哪一个 Widget 替换就可以用上面的方法。
import 'package:flutter/material.dart';
import './tuts.dart';
class TutManager extends StatefulWidget {
final String startingTut;
TutManager({this.startingTut = 'default tut'});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TutManagerState();
}
}
class _TutManagerState extends State<TutManager> {
List<String> _tuts = [];
@override
void initState() {
// TODO: implement initState
_tuts.add(widget.startingTut);
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: [
Container(
margin: EdgeInsets.all(10.0),
child: RaisedButton(
color: Theme.of(context).primaryColor,
onPressed: () {
setState(() {
_tuts.add("Dart");
});
},
child: Text('Add Tut'),
),
),
Tuts(_tuts),
],
);
}
}