Flutter在底层做了大量的渲染化工作、我们只需要通过组合、嵌套不同类型的Widget、就可以构建出任意功能、任意复杂度的界面。
Widget有StatelessWidget和StatefulWidget两种类型。StatefulWidget应对有交互、需要动态变化视觉效果的场景。而StatelessWidget用于处理静态的、无状态的视图展示。在构建界面过程中,会大量使用StatefulWidget来处理静态的视图展示需求。
UI编程方式
- 如何调整一个控件(Widget)的展示样式,UI编程范式
- 原生和JavaScript,视图开发是命令式的。需要精确的告诉操作系统或浏览器用何种方式去做事情。假如想要修改某个界面的某个文案,需要找到具体的文本控件并调用他的控件方法命令。才能完成文字变更
- Flutter的视图开发时声明式的。其核心思想就是将视图和数据分离。
- 设计好Widget布局方案之外、还需要提前维护一套文案数据集。并为需要变换的Widget绑定数据集中的数据。使Widget根据这个数据完成渲染
- 需要变更界面文案时,只需要改变数据集中的文案数据。并通知Flutter框架触发Widget的重新渲染即可。开发者无需再精确关注UI编程中的各个过程细节。只需维护好数据集即可。
- 命令式编程强调精确控制过程细节,而声明式编程强调通过意图输出结果整体。
- 对应到Flutter中,意图是绑定了组件状态的State、结果是重新渲染后的组件。在Widget的生命周期内,应用到State中的任何更改都将强制Widget重新构建。
- 对于组件完成创建后就无需变更的场景。状态的绑定是可选项。这里可选就区分出了Widget的两种类型。即StatelessWidget不带绑定状态。而StatefulWidget带绑定状态。
当你所要构建的用户界面不随任何状态信息的变化而变化时,需要选择使用StatelessWidget,反之则选用StatefulWidget。前者一般用于静态内容的展示,而后者则用于存在交互反馈的内容呈现中。
StatelessWidget
在Flutter中,Widget采用由父到子、自顶向下的方式进行构建。父Widget控制着子Widget的显示样式,其样式配置由父Widget在构建时提供。
- 用这种方式构建出的Widget,有些(Text、Container、Row、Column等)在创建时,除了这些配置参数之外不依赖与其他任何信息。一旦创建成功,不关心,也不响应任何数据变化进行重绘。这样的Widget被称为StatelessWidget(无状态组件)
class Text extends StatelessWidget {
// 构造方法及属性声明部分
Const Text(this.data,{
key key,
this.textAlign,
this.textDirection,
// 其他参数
...
}):assert(data != null),
textSpan = null,
super(key: key);
final String data;
final TextAlign textAlign;
final TextDirection textDirection;
//其他属性
...
@override
Widget build(BuildContext context) {
...
Widget result = RichText(
// 初始化配置
....
)
);
...
return reslut;
}
}
父Widget是否能通过初始化参数完全控制其UI展示效果?如果能。就可以使用StatelessWidget来设计构造函数接口
StatefulWidget
与StatelessWidget相对应的。有些Widget(比如image、Checkbox)的展示,除了父Widget初始化时传入的静态配置之外、还需要处理用户的交互、(比如、用户点击按钮)或其他内部数据的变化,比如网络数据回包,并体现在UI上。
- 这些Widget创建完成后,还需要关心和响应数据变化来进行重绘。这一类Widget被称为StatefulWidget(有状态组件)。
- StatefulWidget是以State类代理Widget构建的设计方式实现的。以Image部分源码为例,说明StatefulWidget的构建过程。
- Image类的构造函数会接收要被这个类使用的属性参数。Image类并没有build方法来创建视图,而是通过CreatState方法创建了一个类型为_ImageState的state对象。然后由这个对象负责视图的创建、
- state对象持有并处理了Image类中的状态变化。从_imageInfo属性来说明
_imageInfo属性用来Widget加载真实的图片,一旦State对象通过_handleImageChanged方法监听到_imageInfo属性发生了变化。就会立即调用_ImageState类的setState方法通知Flutter框架:我这的数据变了。请使用更新后的_imageInfo数据重新加载图片。Flutter框架则会标记视图状态。更新UI ``` class Image extends StatefulWidget { //构造方法及属性声明部分 const Image({ key key, @required this.image, // 其他参数 }) : assert(image != null),
super(key: key);
final ImageProvider image; // 其他属性 …
@override _ImageState createState() => _ImageState(); … }
class_ImageState extends State {
ImageInfo _imageInfo;
// 其他属性
…
void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall){ setState(() { _imageInfo = imageInfo; }); } …
@override Widget build(BuildContext context) { final RawImage image = RawImage( image:_imageInfo?.image, // 其他初始化配置 … ); return image; } … }
Image以一种动态的方式运行,监听变化、更新视图、与StatelessWidget通过父Widget完全控制UI展示不同。 StatefulWidget的父Widget仅定义了它初始化状态。而其自身视图运行的状态则需要自己处理。并根据处理情况 及时更新UI展示。 ```
StatefulWidget不是万金油、要慎用
- SatefulWidget的滥用会直接影响Flutter应用的渲染性能。
- 如果我们的根布局是一个StatefulWidget,再其State中每次调用一次更新UI、都将是一整个页面所有的Widget的销毁和重建、
- 正确评估你的视图展示需求,避免无所谓的StatefulWidget使用。是提高Flutter应用渲染性能最简单也是最直接的手段。
- 除了我们主动的通过State刷新UI之外,在一些特殊的场景下,Widget的bulid方法可能执行多次。因此,我们不应该在方法内部,放置太多耗时的操作。