2

I am trying to ignore multi-finger touches (2-finger specifically) on a Button by wrapping it with IgnorePointer() like so:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: '1 touch'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool isSingleTouch = true;

  @override
  Widget build(BuildContext context) {
    return IgnorePointer(
        ignoring: !isSingleTouch,
        child: RaisedButton(
          onPressed: () {
            print("Button Tapped");
          },
          child: Text("Tap with max 1 finger."),
        ));
  }
}

I want isSingleTouch to be true when the user uses one finger but false when he uses two fingers. Is there any way to get the number of fingers and if it is 2 then make the button fail the hit test?

Foti Dim
  • 1,303
  • 13
  • 19

1 Answers1

1

Please check the below example to detect two figure touch. You can modify it as per your requirement.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Swipe Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Container(
          margin: EdgeInsets.only(top: 100),
          child: MultiTouchPage(
            backgroundColor: Colors.white,
            borderColor: Colors.amber,
            minTouches: 2,
            onTapCallback: (touchCount, correct) {
              print("Touch" + touchCount.toString());
            },
          ),
        ),
      ),
    );
  }
}

class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer {
  MultiTouchGestureRecognizerCallback onMultiTap;
  var numberOfTouches = 0;
  int minNumberOfTouches = 0;

  MultiTouchGestureRecognizer() {
    super.onTapDown = (pointer, details) => this.addTouch(pointer, details);
    super.onTapUp = (pointer, details) => this.removeTouch(pointer, details);
    super.onTapCancel = (pointer) => this.cancelTouch(pointer);
    super.onTap = (pointer) => this.captureDefaultTap(pointer);
  }

  void addTouch(int pointer, TapDownDetails details) {
    this.numberOfTouches++;
  }

  void removeTouch(int pointer, TapUpDetails details) {
    if (this.numberOfTouches == this.minNumberOfTouches) {
      this.onMultiTap(numberOfTouches, true);
    } else if (this.numberOfTouches != 0) {
      this.onMultiTap(numberOfTouches, false);
    }

    this.numberOfTouches = 0;
  }

  void cancelTouch(int pointer) {
    this.numberOfTouches = 0;
  }

  void captureDefaultTap(int pointer) {}

  @override
  set onTapDown(_onTapDown) {}

  @override
  set onTapUp(_onTapUp) {}

  @override
  set onTapCancel(_onTapCancel) {}

  @override
  set onTap(_onTap) {}
}

typedef MultiTouchGestureRecognizerCallback = void Function(
    int touchCount, bool correctNumberOfTouches);


class MultiTouchPage extends StatefulWidget {
  final MultiTouchPageCallback onTapCallback;
  final int minTouches;
  final Color backgroundColor;
  final Color borderColor;


  MultiTouchPage(
      {this.backgroundColor,
        this.borderColor,
        this.minTouches,
        this.onTapCallback});
  @override
  _MultiTouchPageState createState() => _MultiTouchPageState();
}

class _MultiTouchPageState extends State<MultiTouchPage> {
  bool correctNumberOfTouches;
  int touchCount;
  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      gestures: {
        MultiTouchGestureRecognizer:
        GestureRecognizerFactoryWithHandlers<MultiTouchGestureRecognizer>(
              () => MultiTouchGestureRecognizer(),
              (MultiTouchGestureRecognizer instance) {
            instance.minNumberOfTouches = widget.minTouches;
            instance.onMultiTap =
                (touchCount, correctNumberOfTouches,) => this.onTap(touchCount, correctNumberOfTouches);
          },
        ),
      },
      child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Expanded(
              child: Container(
                padding: EdgeInsets.all(12.0),
                decoration: BoxDecoration(
                  color: widget.backgroundColor,
                  border: Border(
                    top: BorderSide(width: 1.0, color: widget.borderColor),
                    left: BorderSide(width: 1.0, color: widget.borderColor),
                    right: BorderSide(width: 1.0, color: widget.borderColor),
                    bottom: BorderSide(width: 1.0, color: widget.borderColor),
                  ),
                ),
                child: Text(
                    "Tap with " +
                        this.touchCount.toString() +
                        " finger(s).",
                    textAlign: TextAlign.center),
              ),
            ),
          ]),
    );
  }

  void onTap(int touchCount, bool correctNumberOfTouches) {
    this.correctNumberOfTouches = correctNumberOfTouches;
    setState(() {
      this.touchCount = touchCount;
    });
    print("Tapped with " + touchCount.toString() + " finger(s)");
    widget.onTapCallback(touchCount, correctNumberOfTouches);
  }

}

typedef MultiTouchPageCallback = void Function(int touchCount, bool correctNumberOfTouches);
Sanjay Sharma
  • 3,687
  • 2
  • 22
  • 38
  • Sanjay thank you for the answer. I need to use IgnorePointer for my use case. Your answer does not help in that direction I am afraid. – Foti Dim Jul 04 '20 at 16:56
  • I think when you detect 2 finger click by the user by this code and then you can change the state by changing the value of isSingleTouch. Can't you? – Sanjay Sharma Jul 04 '20 at 16:59
  • Here, I modified your example to add a button that should be tappable only when using a single finger. There seems to be some state handling issue which I cannot figure out. https://gist.github.com/fotiDim/37e592f907b1e979e3152dc156504e33 – Foti Dim Jul 04 '20 at 17:28
  • You should not do it like this as the button does not handle two touch gesture as you want. You need to create a custom container to represent as a button and then you need to check if the global position of the touch Is inside the container and the do appropriate action for it. – Sanjay Sharma Jul 04 '20 at 17:51
  • The global position of the touch will always be within the container. Assume that the container is full screen. Also replacing the button with a container is not a solution for me as in my real life example I am using other more complicated widgets underneath. I only used a button here for the sake of simplicity. I updated my question to make the example more concrete. Please consider updating your answer if you have a working example. – Foti Dim Jul 04 '20 at 18:10