
import 'dart:math'
import 'package:flutter/material.dart'
///云台控制器
class CircularController extends StatelessWidget {
final Function()? onUpClick
final Function()? onDownClick
final Function()? onLeftClick
final Function()? onRightClick
CircularController({
Key? key,
@required this.onUpClick,
@required this.onDownClick,
@required this.onLeftClick,
@required this.onRightClick,
}) : super(key: key)
//大圆半径
double largeRadius = 100.0
//小圆半径
double smallRadius = 20.0
//图标到顶端的间隔,自由设置
double interval = 40 / sqrt(2)
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: (details) {
// 获取点击位置的坐标
final RenderBox renderBox = context.findRenderObject() as RenderBox
final localPosition = renderBox.globalToLocal(details.globalPosition)
// 计算点击位置相对于中心的角度
final double dx = localPosition.dx - largeRadius
final double dy = localPosition.dy - largeRadius
final double distanceToCenter = sqrt(dx * dx + dy * dy)
final double angle = atan2(dy, dx)
if (distanceToCenter <= smallRadius) {
// 如果点击位置距离中心小于白色小圆的半径,表示点击在白色小圆内部,不处理点击事件
return
}
// 根据角度判断点击的是哪个扇形块
if (angle >= -pi / 4 && angle < pi / 4) {
// 点击了右侧扇形块
// 处理点击右侧扇形块的逻辑
onRightClick!()
} else if (angle >= pi / 4 && angle < 3 * pi / 4) {
// 点击了下方扇形块
// 处理点击下方扇形块的逻辑
onDownClick!()
} else if (angle >= -3 * pi / 4 && angle < -pi / 4) {
// 点击了上方扇形块
// 处理点击上方扇形块的逻辑
onUpClick!()
} else {
// 点击了左侧扇形块
// 处理点击左侧扇形块的逻辑
onLeftClick!()
}
},
child: SizedBox(
width: largeRadius * 2,
height: largeRadius * 2,
child: Stack(
children: [
// 自定义绘制
CustomPaint(
size: Size(largeRadius * 2, largeRadius * 2),
painter: CircularControllerPainter(),
),
// 白色小圆
Center(
child: Container(
width: smallRadius * 2,
height: smallRadius * 2,
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: interval),
child: const Align(
alignment: Alignment.topCenter,
child: Icon(Icons.arrow_upward, color: Colors.black),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: interval),
child: const Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.arrow_downward, color: Colors.black),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: interval),
child: const Align(
alignment: Alignment.centerLeft,
child: Icon(Icons.arrow_back, color: Colors.black),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: interval),
child: const Align(
alignment: Alignment.centerRight,
child: Icon(Icons.arrow_forward, color: Colors.black),
),
),
],
),
),
)
}
}
class CircularControllerIconsPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final double radius = size.width / 2
final Offset center = Offset(size.width / 2, size.height / 2)
// 绘制上下左右图标
final Paint iconPaint = Paint()
..color = Colors.black
..style = PaintingStyle.fill
const double iconSize = 20.0
// 上
canvas.drawCircle(
Offset(center.dx, center.dy - radius + (iconSize / 2)),
iconSize / 2,
iconPaint,
)
// 下
canvas.drawCircle(
Offset(center.dx, center.dy + radius - (iconSize / 2)),
iconSize / 2,
iconPaint,
)
// 左
canvas.drawCircle(
Offset(center.dx - radius + (iconSize / 2), center.dy),
iconSize / 2,
iconPaint,
)
// 右
canvas.drawCircle(
Offset(center.dx + radius - (iconSize / 2), center.dy),
iconSize / 2,
iconPaint,
)
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false
}
}
class CircularControllerPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Paint redPaint = Paint()
..color = Colors.grey
..style = PaintingStyle.fill
final Paint whitePaint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 2.0
final double radius = size.width / 2
final Offset center = Offset(size.width / 2, size.height / 2)
// 绘制四个红色扇形块和白色X形分割线
const double startAngle = -pi / 4
const double sweepAngle = pi / 2
for (int i = 0
final Rect rect = Rect.fromCircle(
center: center,
radius: radius,
)
canvas.drawArc(rect, startAngle + (i * pi / 2), sweepAngle, true, redPaint)
// 绘制白色X形分割线
final double lineStartAngle = startAngle + (i * pi / 2)
final double lineEndAngle = lineStartAngle + sweepAngle
final Offset lineStart1 = Offset(
center.dx,
center.dy,
)
final Offset lineEnd1 = Offset(
center.dx + (radius * cos(lineStartAngle)),
center.dy + (radius * sin(lineStartAngle)),
)
final Offset lineStart2 = Offset(
center.dx,
center.dy,
)
final Offset lineEnd2 = Offset(
center.dx + (radius * cos(lineEndAngle)),
center.dy + (radius * sin(lineEndAngle)),
)
canvas.drawLine(lineStart1, lineEnd1, whitePaint)
canvas.drawLine(lineStart2, lineEnd2, whitePaint)
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false
}
}