-1

I have a circle where each quadrant is mapped to a different condition. Each quadrant will, when tapped, result in a different output/view for the user. From my understanding, I should use Gesture Detector for this. I have this circle both as an svg and I created one using Paint but I'm lost as to how to map the quadrants to Gesture Detector. It seems like the only reliable way to do this would be to make the quadrants of the circle separate objects and then wrap them in a Gesture Detector. Is this correct? If so, is it more efficient to do this in Paint or with an image (or I guess if they were separate objects, it would be 4 images). What are the other (reliable/consistent given varying screen sizes etc) options to solve for this?

circle

import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
//Modified work of Yusuf Patrawala
//How to apply Gesture Detector to each quadrant?

enum QuadrantType { topRight, bottomRight, bottomLeft, topLeft }

class QuadrantCirclePainter extends CustomPainter {

  //Color fill gradients for quadrants
  final topLeftQuadrantColor = Paint()
    ..shader = ui.Gradient.linear(
      Offset(50, 50),
      Offset(140, 140),
      [
        Color(0xffEF8286),
        Color(0xffEE8A7F),
        Color(0xffEB9777),
      ],
      [0.0, 0.5, 1.0],
    );

  final bottomLeftQuadrantColor = Paint()
    ..shader = ui.Gradient.linear(
      Offset(160, 130),
      Offset(80, 180),
      <Color>[
        Color(0xff75E6F0),
        Color(0xff74B2F0),
        Color(0xff7682F0),
      ],
      [0.0, 0.4, 1.0],
    );

  final bottomRightQuadrantColor = Paint()
    ..shader = ui.Gradient.linear(
      Offset(160.0, 0.0),
      Offset(0.0, 160.0),
      <Color>[Color(0xff75BAE4), Color(0xff74D2BF), Color(0xff8DEDAD)],
      [0.0, 0.4, 1.0],
    );

  final topRightQuadrantColor = Paint()
    ..shader = ui.Gradient.linear(
      Offset(0, 200),
      Offset(200, 0),
      <Color>[
        Color(0xffEFBA72),
        Color(0xffEEC674),
        Color(0xffEFD675),
      ],
      [0.0, 0.88, 1.0],
    );

  /// Angle variables
  final double left = math.pi;
  final double top = math.pi + math.pi / 2;
  final double right = 0.0;
  final double bottom = math.pi / 2;
  final double quarterAngle = math.pi / 2; // 1 quadrant = 90 degrees

  final Map<QuadrantType, List<String>?> theText;

  QuadrantCirclePainter({
    required this.theText,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = new Paint()
      ..isAntiAlias = true
      ..strokeWidth = 1.0
      ..style = PaintingStyle.fill;

    final double outerDiameter = size.width;
    final double outerRadius = outerDiameter / 2;

    final arcsRect = Rect.fromLTWH(0, 0, outerDiameter, outerDiameter);
    final useCenter = true;

    double rectSideInsideQuadrant = math.sqrt((outerRadius * outerRadius) / 2);

    /// DRAW QUADRANTS
    /// Top Right Quarter
    canvas.drawArc(arcsRect, top, quarterAngle, true, topRightQuadrantColor);

    /// Bottom Right Quarter
    canvas.drawArc(
        arcsRect, right, quarterAngle, useCenter, bottomRightQuadrantColor);

    /// Bottom Left Quarter
    canvas.drawArc(
        arcsRect, bottom, quarterAngle, useCenter, bottomLeftQuadrantColor);

    /// Top Left Quarter
    canvas.drawArc(
        arcsRect, left, quarterAngle, useCenter, topLeftQuadrantColor);

    /// Function to calculate the bounds of each quadrant
    Rect getQuadrantDrawableBounds(
      QuadrantType quadrantType,
      double quadrantRadius,
      double rectSizeOfQuadrantBound,
      double centerCircleRadius,
    ) {
      Offset offset = Offset(0, 0);
      switch (quadrantType) {
        case QuadrantType.topRight:
          offset = Offset(quadrantRadius + centerCircleRadius,
              quadrantRadius - rectSizeOfQuadrantBound);
          break;
        case QuadrantType.bottomRight:
          offset = Offset(quadrantRadius + centerCircleRadius + 8,
              quadrantRadius + centerCircleRadius + 8);
          break;
        case QuadrantType.bottomLeft:
          offset = Offset(quadrantRadius - rectSizeOfQuadrantBound,
              quadrantRadius + centerCircleRadius);
          break;
        case QuadrantType.topLeft:
        default:
          offset = Offset(quadrantRadius - rectSizeOfQuadrantBound,
              quadrantRadius - rectSizeOfQuadrantBound);
          break;
      }
      return Rect.fromLTWH(
        offset.dx,
        offset.dy,
        rectSizeOfQuadrantBound - centerCircleRadius,
        rectSizeOfQuadrantBound - centerCircleRadius,
      );
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}
4

1 回答 1

0

如果您使用onTapDownon 事件GestureDetector(而不是使用更简单的onTap事件),您将TapDownDetails在回调中获得更多详细信息 ( )。从那里,您可以获得点击事件发生的精确位置,因此您可以自己计算以确定它落入哪个象限。例如,如果x小于总宽度的一半,则表示点击发生在左侧,如果y大于总高度的一半,则表示点击发生在下半部分。结合起来xy你就会知道它是哪个象限。

要使其在不同的屏幕尺寸上正常工作,请使用LayoutBuilder检查小部件的大小,然后x, y根据小部件大小进行计算。例如,如果您的小部件的总宽度为 1000,那么x450 处的则表示点击发生在左半部分。

小部件树看起来像:LayoutBuilder-> GestureDetector> Image,假设您使用Image小部件作为圆形的东西。

我希望这是有道理的,如果您需要代码示例,请告诉我。

于 2022-02-28T05:50:12.723 回答