「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」。
在学习Flutter的时候,我们经常听到或者学习到一句话:万物皆是widget。那么什么是widget呢?
Widget
首先widget一個抽象类,它继承自DiagnosticableTree。
abstract class Widget extends DiagnosticableTree
它主要用于在调试时提供调试信息。
Key
final Key? key;
它是 Element 去识别 Widget 的一个重要标识。Key如果未指定,则为默认值null。key主要的作用是决定是否在下一次build时复用旧的 widget,决定的条件在canUpdate()方法中。
createElement
@protected
@factory
Element createElement();
在构建widget时,会先调用此方法生成对应节点的Element对象。此方法是隐式调用的,在实际开发过程中基本不会用到。通过这里我们可以知道widget创建一个element 元素,也从这里往源码里面挖掘会牵扯出Widget、Element以及RenderObject这三个树,以及他们之间的关系。
toStringShort
/// A short, textual description of this widget.
@override
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
是对该Widget的简短说明,包括Widget的类型和对应的Key等;
debugFillProperties
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
复写父类DiagnosticableTree的方法,主要是设置诊断树的一些特性。如果您编写自己的widget,则可以通过覆盖debugFillProperties()来添加信息。
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IntProperty('_counter', _counter));
}
我们使用了IntProperty,更多的调式属性类型请在文档中查看。在实际的调式中我们可以在Flutter DevTools(详细信息树视图,它显示有关小部件、渲染对象和状态的有用信息)。在这里就能看到刚才我们新添加的_counter。
canUpdate
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key;
}
它主要用于在 Widget 树重新build时复用旧的 widget,如果返回 true 表示可以更新当前 Element 对象,并用新的 widget 更新 Element 的 widget 。返回false 表示不用更新当前Element 对象。
_debugConcreteSubtype
static int _debugConcreteSubtype(Widget widget) {
return widget is StatefulWidget ? 1 : widget is StatelessWidget ? 2 : 0;
}
_debugConcreteSubtype方法返回一个数值,用于指示Widget的实际子类型,1表示StatefulWidget,2表示StatelessWidget ,其他的用0来表示。
operator == 与 hashCode
@override
@nonVirtual
bool operator ==(Object other) => super == other;
@override
@nonVirtual
int get hashCode => super.hashCode;
是当且仅this 对象 和other是同一对象时才返回 true 。但是这里需要注意的是operator ==是被标识为@nonVirtual,当==被当用注释的成员被覆盖时发出提示不能覆盖此方法。这个时候如果我们有这种需求的话,我们可以使用identical。具体的可以看这个issue
operator == 与 identical 的区别
- == 通过对象的 operator ==比较是否相等.
- identical 通过比较两个引用的是否是同一个对象判断是否相等.
hashCode是一个对象的哈希值。
void main() {
var ep1 = IccClass(10);
var ep2 = IccClass(10);
var ep3 = IccClass(20);
print(ep1.hashCode);
print(ep2.hashCode);
print(ep3.hashCode);
print(ep1 == ep2);
print(ep1 == ep3);
print(identical(ep1, ep2));
print(identical(ep1, ep3));
}
class IccClass {
Int id;
IccClass(this.id);
// 步骤1
// bool operator ==(o) => o is IccClass && o.id == id;
// 步骤2
//int get hashCode => id;
}
第一次,不打开步骤1和步骤2,然后运行的结果:
582536759
1000007873
619794939
false
false
false
false
第二次,打开步骤1,不打开步骤2,然后运行的结果:
725718048
507628837
416227163
true
false
false
false
第二次,打开步骤2,不打开步骤1,然后运行的结果:
20
20
20
false
false
false
false
第四次,打开步骤1和步骤2,然后运行的结果:
20
20
20
true
false
false
false