Детектор жестов для квадрантов круга
У меня есть круг, где каждый квадрант сопоставлен с другим состоянием. При нажатии на каждый квадрант для пользователя будет отображаться другой вывод/представление. Насколько я понимаю, я должен использовать для этого. У меня есть этот круг как в формате svg, и я создал его, но я не знаю, как сопоставить квадранты с файлами . Кажется, что единственный надежный способ сделать это — сделать квадранты круга отдельными объектами, а затем обернуть их
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
виджет для круга штучки.
Я надеюсь, что это имеет смысл, дайте мне знать, если вам нужен пример кода.