Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: What is the correct way to detect touch enter, move and exit on CustomPainter objects

I am beginner in Flutter and I am trying to figure how I can detect touch enter, move and exit when a user runs their finger across a custom shape and/or across multiple stacked custom shapes. Something like below

enter image description here

Ideally I would like to get touch events when users enter/exit pixel boundaries of each custom shape, but I wanted to get it working at-least with a MBR of the shapes. Below is the code that I have. What am I doing wrong? All it seems to do is print move when touch begins within the shapes. I have tried GestureDetector too with similar results.

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',
      theme: ThemeData(
        primarySwatch: Colors.deepOrange,
      ),
      home: MyHomePage(title: 'Flutter Demo'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Stack(
              children: <Widget>[
                Listener(
                  onPointerSignal: (PointerEvent details) {
                    print("Signal yellow");
                  },
                  onPointerMove: (PointerEvent details) {
                    print("Move yellow");
                  },
                  onPointerHover: (PointerEvent details) {
                    print("Hover yellow");
                  },
                  onPointerEnter: (PointerEvent details) {
                    print("Enter yellow");
                  },
                  onPointerExit: (PointerEvent details) {
                    print("Exit yellow");
                  },
                  child: CustomPaint(
                    painter: ShapesPainter(),
                    child: Container(
                      height: 400,
                      width: 400,
                    ),
                  ),
                ),
                Listener(
                  onPointerEnter: (PointerEvent details) {
                    print("Enter red");
                  },
                  onPointerExit: (PointerEvent details) {
                    print("Exit red");
                  },
                  child: CustomPaint(
                    painter: ShapesPainter1(),
                    child: Container(
                      height: 200,
                      width: 200,
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class ShapesPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint();
    // set the color property of the paint
    paint.color = Colors.yellow;
    // center of the canvas is (x,y) => (width/2, height/2)
    var center = Offset(size.width / 2, size.height / 2);

    // draw the circle on centre of canvas having radius 75.0
    canvas.drawCircle(center, size.width / 2, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }

  @override
  bool hitTest(Offset position) {
    // TODO: implement hitTest
    return super.hitTest(position);
  }
}

class ShapesPainter1 extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint();
    // set the color property of the paint
    paint.color = Colors.red;
    // center of the canvas is (x,y) => (width/2, height/2)
    var center = Offset(size.width / 2, size.height / 2);

    // draw the circle on centre of canvas having radius 75.0
    canvas.drawCircle(center, size.width / 2, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }

  @override
  bool hitTest(Offset position) {
    // TODO: implement hitTest
    return super.hitTest(position);
  }
}
like image 855
Harkish Avatar asked Jun 29 '19 03:06

Harkish


1 Answers

I have developed a library called touchable for the purpose of adding gesture callbacks to each individual shape you draw on the canvas.

Here's what you can do to detect touch and drag on your circle.

Just Wrap your CustomPaint widget with CanvasTouchDetector. It takes a builder function as argument that expects your CustomPaint widget as shown below.

import 'package:touchable/touchable.dart';


CanvasTouchDetector(
    builder: (context) => 
        CustomPaint(
            painter: MyPainter(context)
        )
)

Inside your CustomPainter class's paint method , create and use the TouchyCanvas object (using the context obtained from the CanvasTouchDetector and canvas) to draw your shape and you can give gesture callbacks like onPanUpdate , onTapDown here to detect your drag events.

var myCanvas = TouchyCanvas(context,canvas);
myCanvas.drawRect( rect , Paint() , onPanUpdate: (detail){
    //This callback runs when you drag this rectangle. Details of the location can be got from the detail object.
    //Do stuff here. Probably change your state and animate
});
like image 161
Natesh bhat Avatar answered Oct 19 '22 18:10

Natesh bhat