Flutter(十三)——事件处理:手势识别与事件通知

前言

在Flutter开发App的过程中,我们除了需要灵活的使用各种组件之外,还需要掌握手势的识别,比如我们常常需要在操作App的时候使用到缩放,双击,放大,缩小等操作,这些Flutter都给我们提供了监听的组件GestureDetector。这篇博文将详细介绍GestureDetector手势识别的使用规则。(拖动手势监听)
拖动组件

GestureDetector基本用法

我们前面提到过,在Flutter开发中,一切皆是组件,所以GestureDetector同样是一个组件,我们使用它,通常是作为一个父Widget包裹一个子Widget外面(也就是你需要捕捉那个组件的手势,就把GestureDetector套在外外面),而内部我们通过onTap回调来实现其点击的效果,代码如下:

GGestureDetector(
	onTap:(){
		print("tap");
	},
	child:Container{
		padding:EdgeInsets.all(20),
		decoration:BoxDecoration(
			color:Theme.of(context).buttonColor,
			borderRadius:BorderRadius.circular(8.0),
		),
		child:new Text("文本"),
	}
);

比如上面的代码就是改造Text组件成为按钮的方式,这里捕捉了点击事件。

常用事件

GestureDetector手势识别不仅仅只有onTap事件,还有很多很多的常用事件,博主通过一张表格将它们全部列举了出来,方便大家查阅:

属性取值意义
onTapDwon当按下屏幕时触发
onTap当与屏幕短暂地触碰时触发,最常用
onTapUp当用户停止触碰屏幕时触发
onTapCancel当用户触摸屏幕,但没有完成Tap事件时触发
onDoubleTap快速双击屏幕时触发
onLongPress当长按屏幕时触发(与屏幕接触事件必须超过500ms)
onPanUpdate当在屏幕上移动时触发
onVerticalDragDown当手指触碰屏幕且准备往屏幕垂直方向移动时触发
onVerticalDragStart当手指触碰屏幕且开始往屏幕垂直方向移动时触发
onVerticalDragUpdate当手指触碰屏幕且开始往屏幕垂直方向移动并发生位移时触发
onVerticalDragEnd当用户完成垂直方向触摸屏幕时触发
onVerticalDragCancel当用户中断了onVerticalDragDown时触发
onHorizontalDragDown当手指触摸屏幕且准备往屏幕水平方向移动时触发
onHorizontalDragStart当手指触摸屏幕且开始往屏幕水平方向移动时触发
onHorizontalDragUpdate当手指触摸屏幕且开始往屏幕水平方向移动并发生位移时触发
onHorizontalDragEnd当用户完成水平方向触摸屏幕时触发
onHorizontalDragCancel当用户中断了onHorizontalDragDown时触发
onPanDown当用户触摸屏幕时触发
onPanStart当用户触摸屏幕并开始移动时触发
onPanUpdate当用户触摸屏幕并产生移动时触发
onPanEnd当用户完成触摸屏幕时触发
onScaleStart当用户触摸屏幕并开始缩放时触发
onScaleUpdate当用户触摸屏幕并产生缩放时触发
onScaleEnd当用户完成缩放时触发

虽然说上面表格非常详细,但其中有些事件是互斥的,并不能同时存在,比如onVerticalUpdate,onHorizontalUpdate,onPanUpdate这些三个事件都不能同时存在,否则会报错。

另外,onPanUpdate和onScaleUpdate也不能同时存在,这是因为在Gesture识别器里,Scale操作是Pan操作的超集。

监听事件实现缩放

既然我们了解了如何使用这些事件,那么,我们就应该实践起来,这里小编将用上面的事件实现一个缩放效果,代码如下:

class _MyHomePageState extends State<MyHomePage>{
  double _top=0.0;
  double _left=0.0;
  double _size=100.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: new Text("忽略事件"),),
      body: Stack(
        children: <Widget>[
          Positioned(
            top: this._top,
            left: this._left,
            child: GestureDetector(
              child: FlutterLogo(
                size: this._size,
              ),
              onScaleUpdate: (e){
                setState(() {
                  this._size=300*e.scale.clamp(.5, 10.0);缩放倍数在0.5到10倍之间
                });
              },
            ),
          ),
        ],
      ),
    );
  }
}

代码非常的简单,就是缩放FlutterLogo的大小,实现的效果如下图所示:
缩放

监听事件实现拖拽

既然我们已经了解这么多事件,不妨多来一个事件,也就是App中常用的拖拽操作,代码如下(略微改改上上面的代码就行):

class _MyHomePageState extends State<MyHomePage>{
  double _top=0.0;
  double _left=0.0;
  double _size=100.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: new Text("忽略事件"),),
      body: Stack(
        children: <Widget>[
          Positioned(
            top: this._top,
            left: this._left,
            child: GestureDetector(
              child: FlutterLogo(
                size: this._size,
              ),
              onPanUpdate: (e){
                setState(() {
                  this._left+=e.delta.dx;
                  this._top+=e.delta.dy;
                });
              },
            ),
          ),
        ],
      ),
    );
  }
}

仅仅改变了事件的代码,前面说过onPanUpdate与onScaleUpdate不能同时存在,所以不能直接添加事件,需要删除onScaleUpdate后在添加。

事件通知

Notification是“通知”的意思,这和Android中不一样。在Flutter里,Notification会沿着当前的context节点从下往上传递,所有父节点都可以通过NotificationListener来监听通知,这种由子向父的传递方式,我们称为“通知冒泡”,并继承至Notification,而父Widget使用NotificationListener进行监听并捕获通知。常用的NotificatioListener有LayoutChangeNotification,SizeChangedLayoutNotifier,ScrollNotification等。比如本篇将监听ListView滚动状态:是通过NotificationListener里的onNotification回调方法来判断状态。代码如下:

class _MyHomePageState extends State<MyHomePage> {
  String _message = "我是通知";
  
  void _onScrollStart(ScrollMetrics scrollMetrics){
    print(scrollMetrics.pixels);
    setState(() {
      this._message="滚动开始";
    });
  }
  
  void _onScrollEnd(ScrollMetrics scrollMetrics){
    print(scrollMetrics.pixels);
    setState(() {
      this._message="滚动结束";
    });
  }
  
  void _onScrollUpdate(ScrollMetrics scrollMetrics){
    print(scrollMetrics.pixels);
    setState(() {
      this._message="滚动进行时";
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: new Text("事件通知"),
      ),
      body: Column(
        children: <Widget>[
          Container(
            height: 50.0,
            color: Colors.green,
            child: Center(
              child: new Text(this._message),
            ),
          ),
          Expanded(
            child: NotificationListener<ScrollNotification>(
              // ignore: missing_return
              onNotification: (scrollNotification) {
                if (scrollNotification is ScrollStartNotification) {
                  this._onScrollStart(scrollNotification.metrics);
                } else if (scrollNotification is ScrollUpdateNotification) {
                  this._onScrollUpdate(scrollNotification.metrics);
                } else if (scrollNotification is ScrollEndNotification) {
                  this._onScrollEnd(scrollNotification.metrics);
                }
              },
              child: ListView.builder(
                  itemCount: 30,
                  itemBuilder: (context, index) {
                    return ListTile(title: Text("索引:$index"),);
                  }),
            ),
          ),
        ],
      ),
    );
  }
}

实现效果如下图所示,代码很好理解,这里就不在赘述了:
事件通知

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李元静

您的鼓励就是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值