How to use GestureDetector's onForcePress properties?

Viewed 592

I'm trying to use the onForcePress properties, e.g. onForcePressStart, onForcePressUpdate etc, of the GestureDetector widget in Flutter, but they are not triggering their callbacks when I touch the screen (as lightly as I can or as forcefully as I dare). I previously implemented my otherwise identical code with onPanStart, onPanUpdate etc, and it worked as expected, just without access to the pressure information I desire.

Minimal working example where the GestureForcePress callbacks don't seem to be called:

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print('onTap triggered');
      },
//      onPanStart: (details) {
//        print('onPanStart triggered with ' + details.toString());
//      },
//      onPanUpdate: (details) {
//        print('onPanUpdate triggered with ' + details.toString());
//      },
      onForcePressStart: (details) {
        print('onForcePressStart triggered with ' + details.toString());
      },
      onForcePressUpdate: (details) {
        print('onForcePressUpdate triggered with ' + details.toString());
      },
      child: Container(
        color: Colors.red,
      ),
    );
  }
}

I'm aware they shouldn't trigger if pressure is less than startPressure, which is 0.4 on a 0 to 1 scale by default for the GestureDetector widget. (I'd also like to know how to edit this startPressure property, but will ask that as a separate question.)

The device I'm testing this on is a Galaxy Note 10+ that readily gives pressure information to other apps.

1 Answers

Traced the origin of the issue to the addAllowedPointer(PointerEvent event) method in force_press.dart, which begins

@override
void addAllowedPointer(PointerEvent event) {
  // If the device has a maximum pressure of less than or equal to 1, it
  // doesn't have touch pressure sensing capabilities. Do not participate
  // in the gesture arena.
  if (event is! PointerUpEvent && event.pressureMax <= 1.0) {
      resolve(GestureDisposition.rejected);
  } else {
      // code for adding ForcePress pointer
  }

The comment stating that devices without pressure sensing capabilities have maximum pressures of <= 1 is not true, with my pressure-sensing device having a maximum pressure of 1.0 (as found by inspecting the PointerDataPackets where pressure first appears in the stack while debugging).

I changed this in my force_press.dart to

@override
void addAllowedPointer(PointerEvent event) {
  // If the device has a maximum pressure of less than or equal to 1, it
  // doesn't have touch pressure sensing capabilities. Do not participate
  // in the gesture arena.
  if (event is! PointerUpEvent && event.pressureMax == event.pressureMin) {
      resolve(GestureDisposition.rejected);
  } else {
      // code for adding ForcePress pointer
  }

as, as stated throughout PointerEvent documentation, devices without pressure sensing capabilities should have pressureMin = 1.0 and pressureMax = 1.0, and a device that did have pressure sensing capabilities with a pressureMin = 1.0, pressureMax = 1.0 would be indistinguishable from one that didn't in all the use cases I can think of, so this made sense to me.

For me, PointerEvents of kind touch, which don't seem to be pressure sensitive, only returning pressures of 1.0 in their PointerDataPackets, return a pressureMin of 0.0 and pressureMax of 1.0, and so trigger the onForcePress callbacks, which beat onPan in the gesture arena. I don't mind this, as I've only encountered situations where ForcePresses with pressure = 1.0 would behave equivalently to onPans with no pressure data, but this might be an issue for someone encountering this in future?

I think, ultimately, non-pressure-sensitive touch events should be registered with pressureMin = 1.0, as the documentation states they are, but I haven't yet figured out how to implement this.

Related