本文是对 Flutter Widget 相关知识的学习和总结。
@immutable
代表 Widget 是不可变的,即Widget 中定义的属性必须是 final。widget
类继承自DiagnosticableTree
,即"诊断树",主要作用是提供调试信息。Key
属性类似于 React/Vue 中的key
,主要的作用是决定是否在下一次build
时复用旧的 widgetcreateElement():
一个 widget 可以对应多个Element,
Flutter框架在构建UI树时,会先调用此方法生成对应节点的Element
对象。abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
@factory
Element createElement();
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
...
}
Flutter 框架的处理流程:(真正的布局、绘制是由谁来完成的)
Element
类。RenderObject
类。Layer
类。widget
类,重写了createElement()
方法build
方法中通过嵌套其他 widget 来构建UIclass MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return Echo(text: "hello world");
}
}
class Echo extends StatelessWidget {
const Echo({
Key? key,
required this.text,
this.backgroundColor = Colors.grey,
}):super(key:key);
final String text;
final Color backgroundColor;
Widget build(BuildContext context) {
return Center(
child: Container(
color: backgroundColor,
child: Text(text),
),
);
}
}
build
方法有一个context
参数BuildContext
类的一个实例,表示当前 widget 在 widget 树中的上下文class ContextRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Context测试"),
),
body: Container(
child: Builder(builder: (context) {
Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
return (scaffold.appBar as AppBar).title;
}),
),
);
}
}
widget
类,重写了createElement()
方法createState()
StatefulElement
具有一一对应的关系abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
StatefulElement createElement() => StatefulElement(this);
State createState();
}
一个 StatefulWidget 类会对应一个 State 类 ,State表示与其对应的 StatefulWidget要维护的状态,State 中保存的状态信息可以:
setState()
方法通知Flutter框架状态发生改变。initState
:**当 widget 第一次插入到 widget 树时会被调用didChangeDependencies()
:**当State对象的依赖发生变化时会被调用build()
:**用于构建 widget 子树reassemble()
:**专门为了开发调试而提供的,在热重载(hot reload)时会被调用didUpdateWidget()
:**在 widget 重新构建时调用deactivate()
:**当 State 对象从树中被移除时调用dispose()
:**当 State 对象从树中被永久移除时调用class CounterWidget extends StatefulWidget {
const CounterWidget({Key? key, this.initValue = 0});
final int initValue;
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void initState() {
super.initState();
_counter = widget.initValue;
print("initState");
}
Widget build(BuildContext context) {
print("build");
return Scaffold(
body: Center(
child: TextButton(
child: Text('$_counter'),
onPressed: () => setState(() => ++_counter),
),
),
);
}
void dispose() {
super.dispose();
print("dispose");
}
}
在子 widget 树中获取父级 StatefulWidget 的State 对象的两种方法:
// 通过context.findAncestorStateOfType获取ScaffoldState
ScaffoldState _state = context.findAncestorStateOfType<ScaffoldState>()!;
_state.openDrawer();
// 通过of静态方法来获取ScaffoldState
ScaffoldState _state=Scaffold.of(context);
_state.openDrawer();
// 1.给目标StatefulWidget添加GlobalKey
static GlobalKey<ScaffoldState> _globalKey= GlobalKey();
...
Scaffold(
key: _globalKey,
...
)
// 2.通过GlobalKey来获取State对象
_globalKey.currentState.openDrawer()
StatelessWidget
和 StatefulWidget
本身没有对应的RenderObjectclass CustomWidget extends LeafRenderObjectWidget{
RenderObject createRenderObject(BuildContext context) {
return RenderCustomObject();
}
}
class RenderCustomObject extends RenderBox{
void performLayout() {
// 实现布局逻辑
}
void paint(PaintingContext context, Offset offset) {
// 实现绘制
}
}
Flutter 提供了一套丰富、强大的基础组件库,在基础组件库之上 Flutter 又提供了:
常用基础组件:
Text
:创建带格式的文本Row
、Column
:在水平和垂直方向上创建灵活的布局Stack
:允许子 widget 堆叠Container
:创建矩形视觉元素import 'package:flutter/material.dart';
MaterialApp
组件开始import 'package:flutter/cupertino.dart';
class CupertinoTestRoute extends StatelessWidget {
const CupertinoTestRoute({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text("Cupertino Demo"),
),
child: Center(
child: CupertinoButton(
color: CupertinoColors.activeBlue,
child: const Text("Press"),
onPressed: () {}
),
),
);
}
}
StatefulWidget
和 StatelessWidget
两种flutter/widgets.dart
了对于iOS开发者来说,在开发Flutter应用时,可以使用appuploader工具来简化应用的上传和发布流程。appuploader是一款专业的iOS开发助手,可以帮助开发者快速完成应用打包、证书管理和App Store上传等工作,大大提高了开发效率。