Flutter:检测CustomPainter对象上的触摸输入,移动和退出的正确方法是什么

时间:2019-06-29 03:23:38

标签: flutter flutter-layout

我是Flutter的初学者,我试图弄清楚当用户的手指越过自定义形状和/或越过多个堆叠的自定义形状时如何检测触摸进入,移动和退出。像下面这样

enter image description here

理想情况下,当用户输入/退出每个自定义形状的像素边界时,我希望获得触摸事件,但是我希望它至少与形状的MBR一起工作。下面是我的代码。我究竟做错了什么?当形状内的触摸开始时,似乎要做的只是打印移动。我也尝试过GestureDetector,结果相似。

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);
  }
}

2 个答案:

答案 0 :(得分:2)

那是因为您每Listener使用一个CustomPainter,所以您的所有Listener应该只使用一个Stack

如果您想知道当前触摸事件是否在每个Circle内部,则可以使用GlobalKey s为每个Circle获取RenderBox,那么您将拥有renderBox和{{ 1}},您可以轻松检查HitTest,检查代码:

PointerEvent

我还修改了class _MyHomePageState extends State<MyHomePage> { GlobalKey _keyYellow = GlobalKey(); GlobalKey _keyRed = GlobalKey(); @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("title"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Listener( onPointerMove: (PointerEvent details) { final RenderBox box = _keyRed.currentContext.findRenderObject(); final RenderBox boxYellow = _keyYellow.currentContext.findRenderObject(); final result = BoxHitTestResult(); Offset localRed = box.globalToLocal(details.position); Offset localYellow = boxYellow.globalToLocal(details.position); if (box.hitTest(result, position: localRed)) { print("HIT...RED "); } else if (boxYellow.hitTest(result, position: localYellow)) { print("HIT...YELLOW "); } }, child: Stack( children: <Widget>[ CustomPaint( key: _keyYellow, painter: ShapesPainter(), child: Container( height: 400, width: 400, ), ), CustomPaint( key: _keyRed, painter: ShapesPainter1(), child: Container( height: 200, width: 200, ), ), ], ), ), ], ), ), ); } } 的{​​{1}}方法,以忽略圆圈外的触摸。

hitTest

答案 1 :(得分:1)

我开发了一个名为 touchable的目的是为您在画布上绘制的每个形状添加手势回调。

在这里您可以执行以下操作来检测圈子中的触摸和拖动。

只需用CanvasTouchDetector包装您的CustomPaint小部件。它使用一个构建器函数作为参数,期望您的CustomPaint小部件如下所示。

import 'package:touchable/touchable.dart';


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

在CustomPainter类的paint方法中,创建并使用TouchyCanvas对象(使用从CanvasTouchDetector和canvas获得的上下文)绘制形状,然后可以在此处提供诸如onPanUpdate,onTapDown之类的手势回调来检测拖动事件。

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
});