flutter学习--手势

flutter中和点击事件相关的分为两大类事件:指针手势

一、指针

描述了屏幕上由触摸板、鼠标、指示笔等触发指针的位置和移动。源码如下:
在这里插入图片描述
常用的指针属性:

  • onPointerDown :指针在特定位置与屏幕接触
  • onPointerMove:指针从屏幕的一个位置移动到另外一个位置
  • onPointerUp:指针与屏幕停止接触
  • onPointerCancel:指针的输入已经不再指向此应用
  • behavior:命中行为,描述哪些区域可以点击。
  • child:子组件
1、简单使用
class PointApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('指针事件'),
      ),
      body: Listener(
        child: Container(
          width: 300,
          height: 300,
          color: Colors.red,
        ),
        onPointerDown: (event) {
          print(event.toString());
        },
        onPointerUp: (event) {
          print(event.toString());
        },
        onPointerMove: (event) {
          print(event.toString());
        },
      ),
    );
  }
}

打印结果如下:
在这里插入图片描述
分别对应PointerDownEventPointerUpEvent

2、behavior使用

注意代码中不能设置背景颜色。

(1) 看如下代码:

class PointApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('指针事件'),
      ),
      body: Listener(
        child: Container(
          width: 300,
          height: 300,
          child: Center(
            child: Text('命中我了'),
          ),
        ),
        onPointerDown: (event) {
          print(event.toString());
        },
      ),
    );
  }
}

测试效果:点击文本以外的区域没有效果,其他区域都是透明区域
在这里插入图片描述
(2) HitTestBehavior.opaque

class PointApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('指针事件'),
      ),
      body: Listener(
        child: Container(
          width: 300,
          height: 300,
          child: Container(
            child: Text('命中我了'),
            alignment: Alignment.center,
            width: 200,
            height: 200,
          ),
        ),
        onPointerDown: (event) {
          print(event.toString());
        },
        //触摸行为
        behavior: HitTestBehavior.opaque,
      ),
    );
  }
}

测试效果:整个点击区域都有效果了
HitTestBehavior.opaque:在命中测试时,将当前组件当不透明处理(即使本身透明)
(3) HitTestBehavior.translucent
没有加该行为的测试代码:

class PointApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('指针事件'),
      ),
      body: Stack(
        children: <Widget>[
          Listener(
            child: Container(
              width: 300,
              height: 300,
              color: Colors.red,
            ),
            onPointerUp: (event) {
              print('外层事件');
            },
          ),
          Listener(
            child: Container(
              width: 200,
              height: 200,
              child: Center(
                child: Text('命中我了'),
              ),
            ),
            onPointerUp: (event) {
              print('内层事件');
            },
          )
        ],
      ),
    );
  }
}

测试效果:
在这里插入图片描述
在内部Listener中添加HitTestBehavior.translucent。代码省略。效果如下:
在这里插入图片描述
HitTestBehavior.opaque:当点击组件透明区域时,可以对自身边界内及底部可视区域都进行命中测试

3、忽略指针事件
  • AbsorbPointer:阻止子组件接收指针事件,本身参与命中测试。
  • IgnorePointer:阻止子组件接收指针事件,本身也不参与命中测试。

(1) AbsorbPointer
代码如下:

class PointApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text('指针事件'),
        ),
        body: Listener(
          child: AbsorbPointer(
              child: Listener(
            child: Container(
              width: 300,
              height: 300,
              color: Colors.red,
            ),
            onPointerDown: (event) {
              print('内部事件');
            },
          )),
          onPointerDown: (event) {
            print('外部事件');
          },
        ));
  }
}

效果如下:只打印外部事件,内部事件不打印。
在这里插入图片描述
(2) IgnorePointer
将上述代码AbsorbPointer改为IgnorePointer。其他不变,再次点击区域发现什么打印都没有。都不参与命中测试。

二、手势

手势事件分为两类:

  • GestureDetector:用于手势识别的功能性组件,可以识别各种手势,是指针事件的语义化封装,内部使用一个或多个GestureRecognizer。
  • GestureRecognizer:通过Listener将原始指针事件转化为语义手势
1、GestureDetector

(1) 属性:
在这里插入图片描述
常用的属性如下:

  • 点击:onTapDown、onTapUp、onTap、onTapCancel
  • 双击:onDoubleTap
  • 长按:onLongPress
  • 纵向拖动:onVerticalDragStart、onVerticalDragUpdate、onVerticalDragEnd
  • 横向拖动:onHorizontalDragStart、onHorizontalDragUpdate、onHorizontalDragEnd
  • 移动:onPanStart、onPanUpdate、onPanEnd。

(2) 简单使用:

class GestureWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('GestureWidget'),
      ),
      body: GestureDetector(
        child: Container(
          width: 300,
          height: 300,
          color: Colors.red,
        ),
        onTap: () {
          print('单击事件');
        },
        onDoubleTap: () {
          print('双击事件');
        },
        onLongPress: () {
          print('长按事件');
        },
      ),
    );
  }
}

(3) 拖动使用:

class GestureState extends State<GestureWidget> {
  double _top;
  double _left;
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('GestureState'),
      ),
      body: GestureDetector(
        child: Stack(
          children: <Widget>[
            Positioned(
              left: _left,
              top: _top,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.green,
              ),
            ),
          ],
        ),
        onPanUpdate: (details) {
          setState(() {
            _left += details.delta.dx;
            _top += details.delta.dy;
          });
        },
      ),
    );
  }
}

效果如下:
在这里插入图片描述

2、GestureRecognizer

常见就是TextSpan中的使用:

class GestureState extends State<GestureWidget> {
  TapGestureRecognizer _recognizer = new TapGestureRecognizer();

  @override
  void dispose() {
    super.dispose();
    //解绑,占用资源
    _recognizer.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text('GestureState'),
        ),
        body: Center(
          child: Text.rich(TextSpan(children: [
            TextSpan(text: '链接:'),
            TextSpan(
                text: 'www.baidu.com',
                style: TextStyle(color: Colors.blue),
                recognizer: _recognizer
                  ..onTap = () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) {
                      return Scaffold(
                        appBar: AppBar(title: Text('recognizer跳转而来')),
                      );
                    }));
                  }),
          ])),
        ));
  }
}

效果如下: 点击链接跳转到下一界面。
在这里插入图片描述

三、手势消歧

  • 在屏幕指定的位置上,可能有多个手势捕捉器。所有的手势捕捉器坚挺了指针输入流事件并判断出特定手势。
  • 在任何时候,识别器都可以宣告失败离开竞技场。如果竞技场中只有一个识别器,那么这个识别器就是胜者。
  • 在任何时候,任何识别器都可以宣告胜利,这将导致这个识别器胜出,其他识别器失败。

比如下面一段代码:

class GestureState extends State<GestureWidget> {
  double _left;
  double _top;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text('GestureState'),
        ),
        body: Center(
          child: GestureDetector(
            child: Stack(
              children: <Widget>[
                Positioned(
                  left: _left,
                  top: _top,
                  child: Container(
                    width: 100,
                    height: 100,
                    color: Colors.red,
                  ),
                )
              ],
            ),
            onPanUpdate: (details) {

              print('移动事件》》》');
            },
            onTap: () {
              print('点击事件》》》');
            },
          ),
        ));
  }
}

同时设置两个回调方法onPanUpdateonTap。但是实际发现onTap最终不会触发回调。这是因为onPanUpdate事件就是胜出的识别器。那么如何同时触发两个回调呢?就要回归原始指针事件了。修改成如下代码就行了:

class GestureState extends State<GestureWidget> {
  double _left;
  double _top;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        appBar: AppBar(
          title: Text('GestureState'),
        ),
        body: Listener(
          onPointerDown: (event){
            print('onPointerDown事件》》》');
          },
          child: GestureDetector(
            child: Stack(
              children: <Widget>[
                Positioned(
                  left: _left,
                  top: _top,
                  child: Container(
                    width: 100,
                    height: 100,
                    color: Colors.red,
                  ),
                )
              ],
            ),
            onPanUpdate: (details) {
              print('移动事件》》》');
            },
           /* onTap: () {
              print('点击事件》》》');
            },*/
          ),
        ));
  }
}

外层套一个Listener,并使用onPointerDown回调替换onTap事件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值