You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
8.1 KiB
Dart

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

library flutterptcontrol;
import 'dart:math' as MATH;
import 'package:flutter/material.dart';
typedef void PtCallback(int status);
//pan-tilt Control
class PtControlWidget extends StatefulWidget {
PtControlWidget(
{@required this.innerRadius, @required this.outerRadius, @required this.callback});
///内径
final double innerRadius;
///外径
final double outerRadius;
///点击回调
final PtCallback callback;
@override
State<StatefulWidget> createState() {
return _PtControlWidgetState();
}
}
class _PtControlWidgetState extends State<PtControlWidget> {
int status = -1;
/*
3.获取控件的坐标:
RenderBox renderBox = anchorKey.currentContext.findRenderObject();
var offset = renderBox.localToGlobal(Offset.zero);
控件的横坐标offset.dx
控件的纵坐标offset.dy
如果想获得控件正下方的坐标:
RenderBox renderBox = anchorKey.currentContext.findRenderObject();
var offset = renderBox.localToGlobal(Offset(0.0, renderBox.size.height));
   控件下方的横坐标offset.dx
   控件下方的纵坐标offset.dy
————————————————
版权声明本文为CSDN博主「笨鸟不飞 ≧≦」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/baidu_34120295/article/details/86495861
*/
//获得本组件中心点对象Point(offset.dx, offset.dy)
//Another exception was thrown: type 'Point<num>' is not a subtype of type 'Point<double>'
MATH.Point getCenterPoint() {
RenderBox renderBox = context.findRenderObject();
//控件中心坐标:(offset.dx, offset.dy)
var offset =
renderBox.localToGlobal(Offset(renderBox.size.width / 2, renderBox.size.height / 2));
print('(offset.dx, offset.dy) = (${offset.dx}, ${offset.dy})');
return MATH.Point<num>(offset.dx.toInt(), offset.dy.toInt());
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanDown: (details) {
//坐标系转换
var x = details.localPosition.dx - widget.outerRadius;
var y = -(details.localPosition.dy - widget.outerRadius);
//判断点击位置是否超出范围
var dis = MATH.Point(x, y).distanceTo(MATH.Point(0, 0));
/*
计算圆周上坐标点的公式,其中圆心坐标(xo,yo)r为圆半径α为0(x,y)为圆上的点
x = xo + r * cos(α)
y = yo + r * sin(α)
原点坐标为(0, 0)x轴向左为正y轴向上为正逆时针方向的8个点的弧度为
0 π * 1/8
1 π * 3/8
2 π * 5/8
3 π * 7/8
4 π * 9/8
5 π * 11/8
6 π * 13/8
7 π * 15/8
*/
// dart 计算原点坐标为(0, 0)x轴向左为正y轴向上为正逆时针方向的8个点的坐标
List listInnerPoint = List.generate(8, (index) {
double _radians = MATH.pi * (index * 2 + 1) / 8;
//print('index = $index');
return {
'x': MATH.cos(_radians) * widget.innerRadius,
'y': MATH.sin(_radians) * widget.innerRadius,
};
});
// dart 计算原点坐标为(0, 0)x轴向左为正y轴向上为正逆时针方向的8个点的坐标
List listOuterPoint = List.generate(8, (index) {
double _radians = MATH.pi * (index * 2 + 1) / 8;
//print('index = $index');
return {
'x': MATH.cos(_radians) * widget.outerRadius,
'y': MATH.sin(_radians) * widget.outerRadius,
};
});
print('listInnerPoint = ${listInnerPoint}');
print('[x, y] = [$x, $y]');
//超出范围
if (dis > widget.outerRadius) {
status = -1;
} else if (dis < widget.innerRadius) {
//还原
status = 8;
} else if (x > listOuterPoint[1]['x'] ||
(y > 0 &&
x > listInnerPoint[1]['x'] &&
y <
listInnerPoint[1]['y'] +
(x - listInnerPoint[1]['x']) / MATH.tan(MATH.pi / 8)) ||
(y < 0 &&
x > listInnerPoint[6]['x'] &&
y >
listInnerPoint[6]['y'] -
(x - listInnerPoint[6]['x']) / MATH.tan(MATH.pi / 8))) {
if (y > listOuterPoint[0]['y'] ||
y > listInnerPoint[0]['y'] &&
x <
listInnerPoint[0]['x'] +
(y - listInnerPoint[0]['y']) / MATH.tan(MATH.pi / 8)) {
//右上
status = 1;
} else if (y > listInnerPoint[7]['y'] ||
y > listOuterPoint[7]['y'] &&
x >
listInnerPoint[7]['x'] +
(listInnerPoint[7]['y'] - y) / MATH.tan(MATH.pi / 8)) {
//右
status = 0;
} else {
//右下
status = 7;
}
} else if (x > listInnerPoint[2]['x'] ||
y > 0 &&
x > listOuterPoint[2]['x'] &&
y > listInnerPoint[2]['y'] + (listInnerPoint[2]['x'] - x) / MATH.tan(MATH.pi / 8) ||
y < 0 &&
x < listInnerPoint[5]['x'] &&
y < listInnerPoint[5]['y'] - (listInnerPoint[5]['x'] - x) / MATH.tan(MATH.pi / 8)) {
if (y > 0) {
//上
status = 2;
} else {
//下
status = 6;
}
} else {
if (y > listOuterPoint[3]['y'] ||
y > listInnerPoint[3]['y'] &&
x >
listOuterPoint[3]['x'] -
(y - listOuterPoint[3]['y']) / MATH.tan(MATH.pi / 8)) {
//左上
status = 3;
} else if (y > listInnerPoint[4]['y'] ||
y > listOuterPoint[4]['y'] &&
x <
listOuterPoint[4]['x'] +
(listInnerPoint[4]['y'] - y) / MATH.tan(MATH.pi / 8)) {
//左
status = 4;
} else {
//左下
status = 5;
}
}
widget.callback(status);
setState(() {});
},
onPanEnd: (details) {
status = -1;
setState(() {});
},
///点击回调
/// status == -1 超出范围
/// status == 0 右
/// status == 1 右上
/// status == 2 上
/// status == 3 左上
/// status == 4 左
/// status == 5 左下
/// status == 6 下
/// status == 7 右下
/// status == 8 还原
/// color: Colors.black12
child: Stack(
children: <Widget>[
Image.asset(
null == widget.callback
? 'images/pt_background_disable.png'
: 'images/pt_background_enable.png',
package: 'flutterptcontrol'),
status == 0
? Image.asset('images/pt_right.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 1
? Image.asset('images/pt_right_top.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 2
? Image.asset('images/pt_top.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 3
? Image.asset('images/pt_left_top.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 4
? Image.asset('images/pt_left.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 5
? Image.asset('images/pt_left_bottom.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 6
? Image.asset('images/pt_bottom.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
status == 7
? Image.asset('images/pt_right_bottom.png', package: 'flutterptcontrol')
: SizedBox.shrink(),
// status == 8
// ? Image.asset('images/pt_center.png', package: 'flutterptcontrol')
// : SizedBox.shrink(),
],
),
);
}
}