1.1:Widget的状态
-
Widget的本身没有可变状态(所有字段都必须是final)。
-
如果您希望将一个widget拥有可变状态,请考虑使用 StatefulWidget,每当它被加载为元素并合并到渲染树中时,会创建State对象(通过StatefulWidget.createState)。
-
StatefulWidget和State,用于可以在其生命周期内多次构建的widget。
-
StatelessWidget,用于在给定配置和环境的状态的下始终以相同方式构建的widget。
1.2: StatelessWidget 无状态组件
该类的本身非常简洁,由于Widget有一个createElement抽象方法,
StatelessWidget类中通过StatelessElement对象完成了该抽象方法,
所以StatelessWidget只需要关注build这个抽象方法即可。
Stateless.png
初始项目中,MyApp是继承了StatelessWidget,它的任务在于重写build方法。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
1.3:StatefulWidget有状态组件
Stateful.pngclass MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
//State对象中有一个泛型,从源码中来看,该泛型值接受StatefulWidget,
//即有状态组件类。State作为一个抽象类,存在一个build抽象方法来返回一个Widget对象
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),//widget属性其实就是MyHomePage
),
//略...
);
}
}
Icon源码
Icon类中主要做了四件事:
构造函数--> 声明属性字段--> 实现build方法,返回Widget对象-->debugFillProperties
class Icon extends StatelessWidget {
const Icon(
this.icon, {
Key key,
this.size,
this.color,
this.semanticLabel,
this.textDirection,
}) : super(key: key);
final IconData icon;
final double size;
final Color color;
final String semanticLabel;
final TextDirection textDirection;
@override
Widget build(BuildContext context) {
//暂略...
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
//暂略...
}
}
可以看出,构造函数中有一个必须的参数icon,从定义中来看是一个IconData对象
注意:构造函数用const关键字修饰,字段全被修饰为final,这就意味着字段不可再修改。
这也是被称为无状态的原因,一旦对象构建完成,它就样子就无法再被改变。
CheckBox源码简析
class Checkbox extends StatefulWidget {
const Checkbox({
Key key,
@required this.value,
this.tristate = false,
@required this.onChanged,
this.activeColor,
this.checkColor,
this.materialTapTargetSize,
}) : assert(tristate != null),
assert(tristate || value != null),
super(key: key);
final bool value;//是否选中
final ValueChanged<bool> onChanged;//点击回调
final Color activeColor;//激活态框颜色
final Color checkColor;//激活态对勾颜色
final bool tristate;//三态
final MaterialTapTargetSize materialTapTargetSize;
static const double width = 18.0;
@override
_CheckboxState createState() => _CheckboxState();
}
- 1.构造函数用const修饰,每行写一个属性
- 2.必须的属性用@required注解
- 3.非空的属性用assert断言
- 4.字段全是final类型
_CheckboxState中的build方法返回_CheckboxRenderObjectWidget对象
CheckBox具体绘制逻辑及状态改变,在_RenderCheckbox中实现
---->[flutter/packages/flutter/lib/src/material/checkbox.dart:140]----
class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
//略...
}
return _CheckboxRenderObjectWidget(
//略...
);
}
}
---->[flutter/packages/flutter/lib/src/material/checkbox.dart:168]----
class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
//略...
@override
_RenderCheckbox createRenderObject(BuildContext context) => _RenderCheckbox(
//略...
);
@override
void updateRenderObject(BuildContext context, _RenderCheckbox renderObject) {
//略...
}
_RenderCheckbox继承自RenderToggleable,可以重写paint方法
这边简单看一下主要的边框和对勾的绘制方法
// 可以看出画笔的颜色是checkColor,以线条的形式
void _initStrokePaint(Paint paint) {
paint
..color = checkColor
..style = PaintingStyle.stroke
..strokeWidth = _kStrokeWidth;
}
//绘制边线
void _drawBorder(Canvas canvas, RRect outer, double t, Paint paint) {
assert(t >= 0.0 && t <= 0.5);
final double size = outer.width;
// 当t从0.0到1.0时,逐渐填充外部矩形。
final RRect inner = outer.deflate(math.min(size / 2.0, _kStrokeWidth + size * t));
canvas.drawDRRect(outer, inner, paint);
}
//绘制对勾
void _drawCheck(Canvas canvas, Offset origin, double t, Paint paint) {
assert(t >= 0.0 && t <= 1.0);
final Path path = Path();
const Offset start = Offset(_kEdgeSize * 0.15, _kEdgeSize * 0.45);//起始偏移点
const Offset mid = Offset(_kEdgeSize * 0.4, _kEdgeSize * 0.7);//中间偏移点
const Offset end = Offset(_kEdgeSize * 0.85, _kEdgeSize * 0.25);//终止偏移点
if (t < 0.5) {//t<0.5时,绘制短边
final double strokeT = t * 2.0;
final Offset drawMid = Offset.lerp(start, mid, strokeT);
path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
path.lineTo(origin.dx + drawMid.dx, origin.dy + drawMid.dy);
} else {//t>0.5时,绘制长边
final double strokeT = (t - 0.5) * 2.0;
final Offset drawEnd = Offset.lerp(mid, end, strokeT);
path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
path.lineTo(origin.dx + mid.dx, origin.dy + mid.dy);
path.lineTo(origin.dx + drawEnd.dx, origin.dy + drawEnd.dy);
}
canvas.drawPath(path, paint);
}
网友评论