Flutter中使用Listener来监听相关触摸事件,一次完整的事件包括:手指按下、手指滑动、手指离开。使用Listener可监听各个阶段的事件。
一、Listener
Listener({
Key key,
...
this.onPointerDown, // 手指按下触发
this.onPointerMove, // 移动手指触发
this.onPointerUp, // 手指抬起触发
this.behavior = HitTestBehavior.deferToChild, // //在命中测试期间如何表现
Widget child,
})
使用示例:
import 'package:flutter/material.dart';
class ListenerDemo extends StatefulWidget{
@override
_ListenerDemoState createState() => _ListenerDemoState();
}
class _ListenerDemoState extends State<ListenerDemo>{
Offset offset = Offset(0.0, 0.0);
String status = 'noPoint';
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Listener(
child: Container(
width: 300.0,
height: 200.0,
color: Theme.of(context).primaryColor,
margin: EdgeInsets.only(bottom: 30.0),
child: Text(
'在此区域滑动',
style: TextStyle(
color: Color(0xffffffff),
fontSize: 26
),
),
alignment: Alignment.center,
),
onPointerDown: (event) {
setState(() {
status = 'pointDown';
offset = event.position;
});
},
onPointerMove: (event) {
setState(() {
status = 'pointMove';
offset = event.position;
});
},
onPointerUp: (event) {
setState(() {
status = 'pointUp';
offset = event.position;
});
},
),
Text(
'$status:$offset',
style: TextStyle(
fontSize: 22.0
),
),
],
),
);
}
}
运行效果:
其中回调函数的event参数包含了一写相关信息:
- position:触控点相对于当对于全局坐标的偏移。
- localPosition: 触控点相对于当前widget的坐标的偏移。
- delta:两次指针移动事件(PointerMoveEvent)的距离。
二、behavior属性
behavior决定子Widget如何响应命中测试,它的值类型为HitTestBehavior,这是一个枚举类,有三个枚举值:
- deferToChild:默认值。子widget会一个接一个的进行命中测试,如果子Widget中有测试通过的,则当前Widget通过,这就意味着,如果指针事件作用于子Widget上时,其父(祖先)Widget也肯定可以收到该事件。
- opaque:在命中测试时,将当前Widget当成不透明处理(即使本身是透明的),最终的效果相当于当前Widget的整个区域都是点击区域。
Listener(
// behavior: HitTestBehavior.opaque,
child: Container(
width: 300.0,
height: 200.0,
margin: EdgeInsets.only(bottom: 30.0),
child: Center(
child: Text('在此区域滑动',
style: TextStyle(color: Color(0xff000000), fontSize: 26)
),
),
alignment: Alignment.center,
),
)
上述示例只有手指在文字上滑动才会触发相关事件,如果要想整个300x200的Container都能触发触摸事件的话,可以将behavior
设置为HitTestBehavior.opaque
。
- translucent:当点击透明区域时,可以对底部widget进行命中测试,这意味着底部widget也可以接收事件。
Stack(
alignment: Alignment.center,
children: <Widget>[
Listener(
child: Container(
constraints: BoxConstraints.tight(Size(300, 200)),
decoration: BoxDecoration(
color: Colors.blue
),
),
onPointerDown: (event) => print('one'),
),
Listener(
child: Container(
constraints: BoxConstraints.tight(Size(150, 100)),
child: Center(
child: Text('点击区域', style: TextStyle(color: Colors.white),),
),
),
onPointerDown: (event) => print('two'),
// behavior: HitTestBehavior.translucent,
)
],
)
在上例中,如果点带有文字的Container的非文字区域,控制台只会打印’two’,如果将behavior
放开,点击Container的非文字区域时,控制台依次打印’two’、‘one’ 。
三、忽略PointerEvent
通过IgnorePointer或AbsorbPointer可以组织child接受事件,也就是阻断事件的触发。下面例子中通过切换AbsorbPointer或IgnorePointer的状态实现按钮在可点击与不可点击两种状态之间的切换。
class AbsorbPointerDemo extends StatefulWidget{
@override
_AbsorbPointerDemoState createState() {
// TODO: implement createState
return _AbsorbPointerDemoState();
}
}
class _AbsorbPointerDemoState extends State<AbsorbPointerDemo>{
bool _absorb = false;
int _count = 0;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'开启absorbing/ignoring属性'
),
Switch(
value: _absorb,
onChanged: (val) {
setState(() {
_absorb = val;
});
},
)
],
),
AbsorbPointer(
absorbing: _absorb,
child: RaisedButton(
child: Text(
'AbsorbPointer-button'
),
onPressed: () => setState(() => _count++),
),
),
IgnorePointer(
ignoring: _absorb,
child: RaisedButton(
child: Text(
'IgnorePointer-button'
),
onPressed: () => setState(() => _count++),
),
),
SizedBox(height: 30,),
Text('count: $_count',style: TextStyle(fontSize: 20.0),)
],
);
}
}
运行效果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。