微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

【Flutter】二十五、Flutter的事件处理


    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] 举报,一经查实,本站将立刻删除。

相关推荐