???? 0
咱们所做进去的App,不能仅仅是一幅静止不动的画面!想一下你生存中的这些场景:
- 手机衰弱App上的步数随着你的幸(huang)苦(dong)运(shou)动(bi)而减少;
- 手机时钟App里的秒表计数随着工夫的飞快流逝而扭转;
- 进度条缓缓延长;
如果这些App是用Flutter编写成的,那么这些Widget的“状态”就在随着用户的操作而产生扭转。
StatefulWidget
就是有状态的Widget
。它在程序运行时,状态被容许产生扭转。
只有状态可能产生扭转的StatefulWidget
能力让页面不再变化无穷。也就是说,要想编写出可能被用户操作的App,就必须要应用StatefulWidget
。
???? 目录
- ???? Here's the code!
- ???? 了解
StatefulWidget
和State
- ???? 当咱们
setState(() {});
时,Flutter在幕后帮咱们做了什么?
???? 1
Here's the code!
咱们要实现这样的一个计数器:
咱们实现了一个简略的计数器,画面两头的数字随着咱们按动左下角的蓝色按钮而递增。
main.dart
如下:
import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatefulWidget { @override State<MyApp> createState() { return MyAppState(); }}class MyAppState extends State<MyApp> { var _counter = 0; @override Widget build(BuildContext buildContext) { return MaterialApp( title: '计数器', home: Scaffold( appBar: AppBar( title: Text('计数器') ), body: Center( child: Text( '$_counter', style: TextStyle(fontSize: 30) ) ), floatingActionButton: FloatingActionButton( onPressed: () => setState(() => _counter += 1), child: Icon(Icons.add) ), ) ); }}
代码来得太快,就像龙卷风?不要胆怯,让咱们一点一点分析它。
???? 2
了解StatefulWidget
和State
结尾,我引入了package:flutter/material.dart
,这外面蕴含了Flutter曾经封装好的Material格调的Widget
。
import 'package: flutter/material.dart'
接下来,是经典的runApp()
,这个时候把我编写好的MyApp
(继承了StatefulWidget
)的实例作为参数传入。
void main() => runApp(MyApp());
而后在MyApp
内,咱们会发现显示的具体内容并不是在这个类外面实现的!
class MyApp extends StatefulWidget { @override State<MyApp> createState() { return MyAppState(); }}
在这个类外面,咱们重写了一个createState()
函数,而后这个函数返回了一个State<MyApp>
,是用户定义的MyAppState
类的实例!
而后MyAppState
是何方神圣呢?
class MyAppState extends State<MyApp> { var _counter = 0; @override Widget build(BuildContext buildContext) { return MaterialApp( title: '计数器', home: Scaffold( appBar: AppBar( title: Text('计数器') ), body: Center( child: Text( '$_counter', style: TextStyle(fontSize: 30) ) ), floatingActionButton: FloatingActionButton( onPressed: () => setState(() => _counter += 1), child: Icon(Icons.add) ), ) ); }}
能够看到了,MyAppState
继承了State<MyApp>
,而在这个类外面,咱们重写了build()
函数,并将这个Widget
的内容写在了这外面。
所以,咱们能够得悉:
StatefulWidget
外面须要重写createState()
函数,这个函数返回一个State<StatefulWidget>
的实例。State<StatefulWidget>
外面须要重写build()
函数,这个函数返回一个Widget
的实例。
然而,咱们会发现,仅仅满足了这些,Widget
的状态还不足以发生变化。回看方才的源码,这里有一行:
onPressed: () => setState(() => _counter += 1)
floatingActionButton
的onPressed
属性定义了这个按钮按完之后会触发什么动作,它的值是一个函数(在Dart内,函数是一等对象)。这个函数它会执行setState(() => _counter += 1)
。那么,这个setState()
是做什么的呢?
???? 3
当咱们setState(() {});
时,Flutter在幕后帮咱们做了什么?
setState(fn)
会先执行咱们传入的函数fn
。- 接下来,
setState()
会将这个组件标记为“脏的”。 - 下一帧时,Flutter会从新执行这个“脏”组件的
build()
函数,将它从新渲染一遍。
在上述计数器程序中setState(fn);
的执行过程。动图为自制,转载请注明出处。图中组件树为了简洁明了,省略了AppBar
和Icon
等Widget
,只注明参加了这个过程的少数几个Widget
也就是说,setState({} ());
才是本程序的点睛之笔。
???? -1
总结
StatefulWidget
就是有状态的Widget
。它在程序运行时,状态被容许产生扭转,要想编写出可能被用户操作的App,就必须要应用StatefulWidget
。- 咱们实现了一个简略的计数器。
StatefulWidget
外面须要重写createState()
函数,这个函数返回一个State<StatefulWidget>
的实例。State<StatefulWidget>
外面须要重写build()
函数,这个函数返回一个Widget
的实例。当咱们执行
setState(fn);
时:setState(fn)
会先执行咱们传入的函数fn
。- 接下来,
setState()
会将这个组件标记为“脏的”。 - 下一帧时,Flutter会从新执行这个“脏”组件的
build()
函数,将它从新渲染一遍。
它的用处是刷新一个组件的状态。