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"),);
                  }),
            ),
          ),
        ],
      ),
    );
  }
}

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

发布了103 篇原创文章 · 获赞 139 · 访问量 92万+

猜你喜欢

转载自blog.csdn.net/liyuanjinglyj/article/details/104132153