1.4.3 Widget源码初识
Widget源码在flutter/lib/src/widgets/framework.dart中,进入Widget源码时,你会意外地发现Widget竟然如此简洁:
Widget是一个抽象类,只有一个抽象方法createElement,返回Element对象,toStringShort返回runtimeType和key的字符串。debugFillProperties顾名思义是调试填充属性,最后是静态方法canUpdate。通过代码可以看出,组件能够更新的条件是新旧两个Widget的runtimeType和key都相等。
abstract class Widget extends DiagnosticableTree { const Widget({ this.key }); final Key key; @protected Element createElement(); @override String toStringShort() { return key == null ? '$runtimeType' : '$runtimeType-$key'; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense; } static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; } }
Widget是一个抽象类,其最重要的当属build抽象方法,其子类也将实现此方法。下面就来看一下Widget的两个非常重要的子类:
StatelessWidget是不变化状态的组件。从下面的源码中可以看出,StatelessWidget通过StatelessElement对象来满足父类的createElement抽象方法,并抽象出build方法返回Widget对象。再看初始项目中继承自StatelessElement的MyApp,是不是亲切许多?
StatefulWidget是有变化状态的组件。从下面的源码中可以看出,StatefulWidget通过StatefulElement对象来满足父类的createElement抽象方法,并抽象出createState方法返回State对象。再看MyHomePage的实现,如果想要一个Widget拥有状态,那么就应该继承自StatefulWidget。其中createState方法返回一个_MyHomePageState对象,用下划线表示是私有的,不愿让外界访问。现在焦点便都在_MyHomePageState这个状态类身上。
State类中要传入一个StatefulWidget子类的泛型,也就是说,它必须和Stateful组件联合使用。它是一个抽象类,只有一个返回Widget对象的build抽象方法。
abstract class State<T extends StatefulWidget> extends Diagnosticable { //略... @protected Widget build(BuildContext context); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), //略...
再回看初始项目中_MyHomePageState的实现逻辑应该就会更清楚了。你应该会感觉它是一个非常好的示例程序:融合了Dart语法、自定义StatelessWidget、自定义StatefulWidget、单子组件Center、多子组件Column等,这些都是Flutter中的常用知识。当你看完本书,建议再重新审视一下初始项目,学而时习,温故知新,也能看到自己的成长。