Flutter widget点击事件和点击态
原文链接
http://tryenough.com/flutter06
跟多教程
http://tryenough.com/type-flutter
你将学到
1.使用Flutter自定义控件,点击态处理
2.Flutter 添加点击手势
3.Flutter 多状态管理
4.一个具体的例子
先看下效果
效果图分析:
- 点击不放开的时候,控件四周出现一个深蓝色的边框
- 放开点击控件颜色会改变颜色,active状态绿色,inactive灰色
实现过程
首先你需要知道的是:
我们处理手势可以使用GestureDetector组件,它是可以添加手势的一个widget,观察它的源码:
class GestureDetector extends StatelessWidget {
GestureDetector({
Key key,
this.child,
this.onTapDown,
this.onTapUp,
this.onTap,
this.onTapCancel,
this.onDoubleTap,
this.onLongPress,
this.onLongPressUp,
this.onVerticalDragDown,
this.onVerticalDragStart,
this.onVerticalDragUpdate,
this.onVerticalDragEnd,
this.onVerticalDragCancel,
this.onHorizontalDragDown,
this.onHorizontalDragStart,
this.onHorizontalDragUpdate,
this.onHorizontalDragEnd,
this.onHorizontalDragCancel,
this.onPanDown,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onPanCancel,
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd,
this.behavior,
this.excludeFromSemantics = false
})
...
可以看到GestureDetector的本质就是一个普通的widget,它拥有很多的手势onTapDown(点下),onTapUp(抬起),onTap(点击)...等,同时也拥有child属性,我们可以利用child绘制界面,利用手势处理点击事件。
首先画出界面的样子:
1.用一个多状态的widget来表示方框,如下:
class TapboxC extends StatefulWidget {
TapboxC({Key key, this.active: false, @required this.onChanged})
: super(key: key);
final bool active; // 分析1
final ValueChanged<bool> onChanged; //分析2 先跳过
_TapboxCState createState() => _TapboxCState();
}
分析:
- 分析1:active保存当前的状态
- 分析2:作为点击事件(onTap),先跳过
2. 实现TapboxC类的状态类_TapboxCState:
你需要提前知道的是:
a. 通过 用Flutter定义stateFul控件 这篇文章,我们知道需要为自定义StatefulWidget实现一个状态state类来处理状态,如果你还没学习过这篇文章,可以先记住这个规则。
b. 调用**setState **方法会触发控件重新绘制
实现状态类:
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) { //定义点击函数
setState(() {
_highlight = true; //手指按下时将_highlight设置为true
});
}
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
void _handleTap() {
widget.onChanged(!widget.active); //先跳过 实现
}
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: _handleTapDown, // 分析 1
onTapUp: _handleTapUp,
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: Container(
child: Center(
child: Text(widget.active ? 'Active' : 'Inactive', // 分析 2
style: TextStyle(fontSize: 32.0, color: Colors.white)),
),
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color:
widget.active ? Colors.lightGreen[700] : Colors.grey[600], //分析3
border: _highlight // 分析 4
? Border.all(
color: Colors.teal[700],
width: 10.0,
)
: null,
),
),
);
}
}
分析:
- 分析1: 处理点击事件的顺序是:down, up, tap, cancel
- 分析2: 根据active的值显示不同的文字
- 分析3: 根据active的值显示不同的背景色
- 分析4: 当_highlight的值为true时显示边框,否则不显示
上面代码中,在点击事件中修改了_highlight的值(代表是否需要高亮),在build方法绘制中Text:根据active的值显示不同的文字和背景色,BoxDecoration:根据是否_highlight=true绘制边框(border)。
上面我们先跳过了_handleTap点击方法中调用的onChanged方法,接下来我们来看一下它的实现:
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return Container(
child: TapboxC(
active: _active,
onChanged: _handleTapboxChanged, //分析1
),
);
}
}
分析:
分析1: 可以看到,这里是将_handleTapboxChanged方法作为参数传递给了上面定义的TapboxC。然后在TapboxC的点击事件中,触发了_handleTapboxChanged方法中的setState方法,重新绘制了控件。
总结
-
这个例子中,ParentWidget 父组建保存了变量_active的值;TapboxC组建保存了_highlight的值,然后_highlight根据_active和_highlight的不同值进行绘制。
-
使用GestureDetector处理了点击事件
-
学习了父子控件如何进行值传递