@[toc]
交互
当小部件的状态发生变化时,状态对象调用setState()来告诉框架重新绘制小部件
创建一个自定义的有状态小部件。将用一个自定义的有状态小部件替换两个无状态小部件-红色实心星形图标及其旁边的数字计数-小部件管理一行,其中包含两个子小部件:IconButton和Text。
class FavoriteWidget extends StatefulWidget {
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
要创建自定义的有状态小部件,需要创建两个类:StatefulWidget和State
state对象包含小部件的状态和build()方法。
要实现自定义有状态小部件,需要创建两个类:
定义从StatefulWidget继承的小部件类
包含小部件状态并定义小部件build()方法的类。它继承自State
本节介绍如何为Lakes应用程序构建名为FavoriteWidget的有状态Widget。第一步是选择如何管理FavoriteWidgets的状态。
步骤1:确定哪个对象管理小部件的状态
小部件的状态可以通过多种方式进行管理,但在我们的示例中,小部件本身(FavoriteWidget)将管理自己的状态。在本例中,切换星形图标是一个独立的操作,不会影响父窗口小部件或其他用户界面,因此小部件可以在内部处理自己的状态。
步骤2:创建StatefulWidget的子类
FavoriteWidget类管理自己的状态,因此它重写createState()以创建状态对象。框架在构建小部件时调用createState()。createState()创建了FavoriteWidgetState的一个实例,将在下一步中实现它。
new Icon(
Icons.star,
color: Colors.red[500],
),
new Text('41')
小工具管理其状态
有时,小部件最好在内部管理其状态。例如,当ListView的内容超过渲染框时,ListView会自动滚动。大多数使用ListView的开发人员不希望管理ListView的滚动行为,因此ListView本身管理其滚动偏移。
class TapboxA extends StatefulWidget {
TapboxA({Key key}) : super(key: key);
@override
_TapboxAState createState() => new _TapboxAState();
}
class _TapboxAState extends State<TapboxA> {
bool _active = false;
void _handleTap() {
setState(() {
_active = !_active;
});
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
_active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: _active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
_TapboxAState类:
管理TapboxA的状态
Definition_Active:确定框当前颜色的布尔值
定义_当框被单击时,handleTap()函数会更新,并调用setState()更新UI
widget的state
实现小部件的所有交互行为
对于父窗口小部件,管理状态并告诉其子窗口小部件何时更新通常是最有意义的。例如,IconButton允许将图标视为可单击的按钮。IconButton是一个无状态小部件,因为我们认为父小部件需要知道按钮是否被单击以采取相应的操作。
在下面的示例中,TapboxB通过回调将其状态导出到其父级。因为TapboxB不管理任何状态,所以它的父类是StatelessWidget。
ParentWidgetState类:
管理TapboxB_活动状态
Implementation_ HandleTapboxChanged(),单击框时调用的方法
当状态更改时,调用setState()更新UI
TapboxB类:
继承StatelessWidget类,因为所有状态都由其父控件处理
当检测到单击时,它会通知父控件
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
混合管理
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
对于某些小部件,mashup管理方法是最有意义的。在这种情况下,有状态小部件管理一些状态,而父小部件管理其他状态。
在TapboxC示例中,单击时,框周围会出现一个深绿色边框。单击时,边框将消失,框的颜色将更改。TapboxC将_活动状态导出到其父控件,但内部管理_突出显示状态。此示例有两个状态对象_PrentWidgetState和_TapboxCState
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}
_ParentWidgetState对象:
管理_活动状态
Implementation_ HandleTapboxChanged(),单击该框时调用
当单击框并_调用setState()以在活动状态更改时更新UI时
_TapboxCState对象:
管理_突出显示状态。
手势检测器监听所有敲击事件。当用户单击时,它会添加高亮显示(深绿色边框);当用户释放时,高亮显示将被删除。
按下、抬起或取消时更新突出显示状态,调用setState()更新UI。
单击时,状态更改将传递给父控件
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
另一个实现可能会在保持活动状态的同时将突出显示的状态导出到父窗口小部件。活动状态是内部的,但如果你要求某人使用TapBox,他们可能会抱怨这没有多大意义。开发人员只关心盒子是否处于活动状态。开发人员可能不关心突出显示是如何管理的,而是倾向于让TapBox处理这些细节。