The Listener is introduced

Listener The main function is to listen for screen touch events, depending on the scope of its sub-component, such as press, move, lift, cancel, etc.

We know that the Flutter component has events only for buttons, so if I need to add events to text or a container I need to use a Listener

Video Tutorial Address

Gesture series video tutorial address

When is a Listener used?

The Listener is used to hide the keyboard when a finger is swiping on the screen, or to listen for events when the finger is pulling down to refresh or load.

In the actual development process, listeners are rarely used to monitor gestures. Generally, GestureDetector is used to monitor gestures or MouseRegion is used to monitor mouse events. MouseRegion is often used in Web development. GestureDetector is often used with apps.

Principle of the Listener

  • When a pointer is pressed, Flutter performs a Hit Test on the application to determine what widgets exist where the pointer touches the screen.
  • The pointer down event (and subsequent events for that pointer) is then distributed to the innermost component discovered by the hit test
  • Events bubble along the innermost component to the root of the component tree
  • There is no mechanism to cancel or stop the bubbling process

Listener constructor

There are three main callbacks that we often use

  • onPointerDown()
  • onPointerMove()
  • onpointUp()
const Listener({
    Key key,
    this.onPointerDown,
    this.onPointerMove,
    // We have to ignore the lint rule here in order to use deprecated
    // parameters and keep backward compatibility.
    // TODO(tongmu): After it goes stable, remove these 3 parameters from Listener
    // and Listener should no longer need an intermediate class _PointerListener.
    // https://github.com/flutter/flutter/issues/36085
    @Deprecated(
      'Use MouseRegion.onEnter instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerEnter,
    @Deprecated(
      'Use MouseRegion.onExit instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerExit,
    @Deprecated(
      'Use MouseRegion.onHover instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerHover,
    this.onPointerUp,
    this.onPointerCancel,
    this.onPointerSignal,
    this.behavior = HitTestBehavior.deferToChild,
    Widget child,
  }) : assert(behavior ! =null),
       _child = child,
       super(key: key);
Copy the code

Listener properties and description

field attribute describe
onPointerDown PointerDownEventListener A callback is triggered when the pointer is pressed
onPointerMove PointerMoveEventListener A callback is triggered when the pointer moves
onPointerUp PointerUpEventListener A callback is triggered when the pointer moves away
onPointerSignal PointerSignalEventListener Called when a pointer signal appears
onPointerCancel PointerCancelEventListener A callback is triggered when a pointer is canceled
onPointerEnter PointerEnterEventListener Callback when pointer enters region (deprecated)
onPointerExit PointerExitEventListener Callback when pointer moves out of area (deprecated)
onPointerHover PointerHoverEventListener Called when the pointer to [onPointerDown] is not triggered
behavior HitTestBehavior How do you behave during hit tests
child Widget Child components

Basic use of Listener

We mainly demonstrate onPointerDown, onPointerMove and onPointerUp here, because these are the three attributes we use most frequently in the normal development process, and the other attributes are also discarded.

import 'package:flutter/material.dart';


class ListenerExample extends StatefulWidget {
  @override
  _ListenerExampleState createState() => _ListenerExampleState();
}

class _ListenerExampleState extends State<ListenerExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Listener"),
      ),
      body: Center(
        child: Stack(
          children: [
            Listener(
              onPointerDown: (event) {
                print("onPointerDown----$event");
              },
              onPointerMove: (event) {
                print("onPointerMove----$event");
              },
              onPointerUp: (event) {
                print("onPointerUp----$event");
              },
              // onPointerSignal: (event) {
              // print("onPointerSignal----$event");
              // },
              // onPointerCancel: (event) {
              // print("onPointerCancel----$event");
              // },
              // onPointerEnter: (event) {
              // print("onPointerEnter----$event");
              // },
              // onPointerExit: (event) {
              // print("onPointerExit----$event");
              // },
              // onPointerHover: (event) {
              // print("onPointerHover----$event");
              // },
              child: Container(
                color: Colors.pink,
                child: Text("Jimi",
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 30
                  ),
                ),
              ),
            ),
            Positioned(
              child: Listener(
                onPointerDown: (event) {
                  print("red---- $event");
                },
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                  child: Text("Jimi"),),),)],),),); }}Copy the code

Console output

Here we click on the orange container and click on the red container again, and they print the following results.

flutter: onPointerDown----PointerDownEvent#128be(position: Offset(204.5.403.5))
flutter: onPointerUp----PointerUpEvent#a9558(position: Offset(204.5.403.5))
flutter: red---- PointerDownEvent#8ffdf(position: Offset(140.5.317.0))
Copy the code

PointerEvent introduction

PointerEvent is the base class for touch, stylus, and mouse events.

In the example above, we know what a Listener is and write a simple case. In the process of using the case, we have an event parameter in the event, and all events ultimately inherit from the PointerEvent. So let’s see what the event parameter does.

PointerEvent constructor

const PointerEvent({
  this.embedderId = 0.this.timeStamp = Duration.zero,
  this.pointer = 0.this.kind = PointerDeviceKind.touch,
  this.device = 0.this.position = Offset.zero,
  Offset? localPosition,
  this.delta = Offset.zero,
  Offset? localDelta,
  this.buttons = 0.this.down = false.this.obscured = false.this.pressure = 1.0.this.pressureMin = 1.0.this.pressureMax = 1.0.this.distance = 0.0.this.distanceMax = 0.0.this.size = 0.0.this.radiusMajor = 0.0.this.radiusMinor = 0.0.this.radiusMin = 0.0.this.radiusMax = 0.0.this.orientation = 0.0.this.tilt = 0.0.this.platformData = 0.this.synthesized = false.this.transform,
  this.original,
}) : localPosition = localPosition ?? position,
     localDelta = localDelta ?? delta;
Copy the code

PointerEvent properties and description

There are many attributes of PointerEvent, but they are rarely used in the actual development process. The corresponding attributes are only used in specific situations.

If we need to make a global hover button we will use position

For graphics software we need buttons, kind, etc

So you can use the corresponding attributes according to the actual application scenario, the following is a detailed description of the attributes of PointerEvent.

There are 29 attributes in total

field attribute describe
embedderId int ID of a platform event
timeStamp Duration Event scheduling time
pointer int Pointer unique identifier, each click will be a new, will not be repeated
kind PointerDeviceKind The type of input device for the pointer event
device int Unique identifier of a device that is used repeatedly in interactions
position Offset The offset of a pointer with respect to global coordinates
localPosition Offset The offset of the pointer relative to the current container coordinates
delta Offset The distance between two pointer movement events
localDelta Offset Distance between two pointer movement events (current container)
buttons int It is * button constants, often used with kind, do brush drawing software is often used this property, if it has a value of 6, kind is PointerDeviceKind invertedStylus, so this means that a horse a stylus
down bool Sets whether the current pointer is pressed
obscured bool Whether to block an application window is officially not implemented
pressure double Press force, used in pressure sensors (such as iPhone 3D Touch), ranging from 0.0 to 1.0
pressureMin double Minimum pressure
pressureMax double Maximum pressure
distance double Detects the distance of the object from the input surface
distanceMin double Limits the minimum distance between the detected object and the input surface
distanceMax double Limits the maximum distance between the detected object and the input surface
size double The size of the area of the screen being pressed
radiusMajor double The radius of the contact ellipse along the principal axis, in logical pixels
radiusMinor double The radius of the contact ellipse along the short axis, in logical pixels
radiusMin double Minimum value of radiusMajor and radiusMinor reports
radiusMax double Maximum value of radiusMajor and radiusMinor reports
orientation double The direction of the detected object (the direction the pointer moves), in radians
tilt double The Angle of tilt of the detected object, in radians
platformData int Opaque platform-specific data associated with an event
synthesized bool Sets whether the event is composed by a Flutter.
transform Matrix4 The transformation used to convert this event from global coordinates
original PointerEvent The original unconverted PointerEvent event before any Transform

Behaviors attribute

Behavior property, which determines how a child responds to a hit test, and has a value of type HitTestBehavior, which is an enumerated class with three enumerated values, okay

HitTestBehavior.deferToChild

The child components are hit tested one by one, and if any of the child components pass the test, the current component passes, which means that if a pointer event is applied to a child component, its parent component must also receive the event.

HitTestBehavior.opaque

Treating the current component as opaque (even if it is transparent) during hit testing results in the effect that the entire area of the current Widget is the click area

HitTestBehavior.translucent

When you click on a component’s transparent region, you can test for hits both within its boundaries and in the bottom viewable region, which means that when you click on the top component transparent region, both the top component and the bottom component receive events

Code demo

import 'package:flutter/material.dart';


class ListenerSimpleExample extends StatefulWidget {
  @override
  _ListenerSimpleExampleState createState() => _ListenerSimpleExampleState();
}

class _ListenerSimpleExampleState extends State<ListenerSimpleExample> with AutomaticKeepAliveClientMixin {

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(
        title: Text("Listener"),
      ),
      body: Center(
        child: Stack(
          children: [
            Listener(
              child: ConstrainedBox(
                  constraints: BoxConstraints.tight(Size(400.200)),
                  child: Container(
                    color: Colors.greenAccent,
                  )
              ),
              onPointerDown: (event) => print("The green box was clicked."),
            ),
            Listener(
              child: ConstrainedBox(
                constraints: BoxConstraints.tight(Size(400.200)),
                child: Center(child: Text("Click on text", style: TextStyle(
                  color: Colors.white,
                  fontSize: 30
                ),)),
              ),
              onPointerDown: (event) => print("Text click event callback"),
              behavior: HitTestBehavior.deferToChild,
              // behavior: HitTestBehavior.opaque,
              // behavior: HitTestBehavior.translucent,() [(), (), (); }}Copy the code

When the attribute is set to HitTestBehavior. DeferToChild console output

We’re going to do this by clicking on the green box and then clicking on the text, so you can see the difference between the three properties

Flutter: The green box was clicked on flutter: the text clicked on the event callbackCopy the code

The result is displayed when the property is set to hitTestBehavior. opaque console

Flutter: text click event callback flutter: text click event callbackCopy the code

When the attribute is set to HitTestBehavior. Translucent console output

Flutter: text clicked event callback Flutter: green box was clicked on flutter: text clicked event callbackCopy the code

conclusion

Listener is an important functional component of Flutter. Its main function is to listen for screen touch events. Event callback can obtain corresponding properties to customize app functions.