Детектор жестов для квадрантов круга

У меня есть круг, где каждый квадрант сопоставлен с другим состоянием. При нажатии на каждый квадрант для пользователя будет отображаться другой вывод/представление. Насколько я понимаю, я должен использовать для этого. У меня есть этот круг как в формате svg, и я создал его, но я не знаю, как сопоставить квадранты с файлами . Кажется, что единственный надежный способ сделать это — сделать квадранты круга отдельными объектами, а затем обернуть их . Это правильно? Если да, то эффективнее ли это делать в или с изображением (или, я думаю, если бы они были отдельными объектами, это было бы 4 изображения). Каковы другие (надежные/согласованные с учетом различных размеров экрана и т. д.) варианты решения этой проблемы?

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

1 ответ

Если вы используете onTapDownсобытие (вместо использования более простого onTapсобытие), вы получите дополнительную информацию ( TapDownDetails) в обратном вызове. Оттуда вы можете получить точную позицию, где произошло событие касания, поэтому вы можете сделать свой собственный расчет, чтобы определить, в какой квадрант оно попало. Например, если меньше половины общей ширины, это означает, что постукивание произошло с левой стороны, а если больше половины общей высоты, касание произошло с нижней половины. Объедините и yвы будете знать, какой это квадрант.

Чтобы он хорошо работал на разных размерах экрана, используйте для проверки размера вашего виджета, а затем основывайте свой x, yрасчет размера виджета. Например, если общая ширина вашего виджета равна 1000, то xна 450 будет означать, что касание произошло на левой половине.

Дерево виджетов будет выглядеть примерно так: LayoutBuilder-> GestureDetector> , если вы используете Imageвиджет для круга штучки.

Я надеюсь, что это имеет смысл, дайте мне знать, если вам нужен пример кода.

Другие вопросы по тегам