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

Har*_*ish 8 flutter flutter-layout

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

在此处输入图片说明

理想情况下,我希望在用户进入/退出每个自定义形状的像素边界时获得触摸事件,但我想让它至少与形状的 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

die*_*per 13

那是因为您使用了一个Listenerper CustomPainter,您应该Listener为所有Stack.

如果你想知道当前的触摸事件是否在每个 Circle 内,你可以使用GlobalKeys 来获取RenderBox每个 Circle 的s ,然后你有 renderBox 和PointerEvent,你可以很容易地检查 HitTest,检查代码:

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,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我还修改了hitTest您的CustomPainters方法以忽略圆圈外的触摸。

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)
    final 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) {
    return true;
  }

  @override
  bool hitTest(Offset position) {
    final Offset center = Offset(200, 200);
    Path path = Path();
    path.addRRect(RRect.fromRectAndRadius(
        Rect.fromCenter(center: center, width: 400, height: 400),
        Radius.circular(center.dx)));
    path.close();
    return path.contains(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) {
    final Offset center = Offset(100, 100);
    Path path = Path();
    path.addRRect(RRect.fromRectAndRadius(
        Rect.fromCenter(center: center, width: 200, height: 200),
        Radius.circular(center.dx)));
    path.close();
    return path.contains(position);
  }
}
Run Code Online (Sandbox Code Playgroud)