Flutter手势识别插件one_dollar_unistroke_recognizer的使用
Flutter手势识别插件one_dollar_unistroke_recognizer的使用
Flutter插件one_dollar_unistroke_recognizer
是一个Dart版本的$1单笔画手势识别器,它基于华盛顿大学的$1 Unistroke Recognizer,并添加了一些增强功能。此插件能够识别基本的几何形状如线、圆、矩形和三角形,同时支持自定义单笔画模板的识别。
主要特点
- Protractor增强:默认启用,可以禁用。
- 获取完美的(标准)形状:从用户绘制的手势中提取出最接近的标准形状。
- 更适合检测直线的算法:改进了对直线的识别能力。
- 类型安全:通过
DefaultUnistrokeNames
枚举或其他自定义类型来保证类型安全。
使用方法
基本使用
final points = <Offset>[...]; // 用户绘制的手势点集合
final recognized = recognizeUnistroke(points);
if (recognized == null) {
print('No match found');
} else {
print('Stroke recognized as ${recognized.name}');
}
禁用Protractor增强
final recognized = recognizeUnistroke(
points,
useProtractor: false,
);
获取“完美”的标准形状
可以通过调用RecognizedUnistroke
对象上的不同方法来获得用户绘制的手势对应的理想形状:
convertToCanonicalPolygon()
: 返回与输入手势最匹配的模板多边形。convertToLine()
: 返回第一个和最后一个输入点,用于表示一条线段。convertToCircle()
: 返回最佳拟合圆的中心和半径。convertToOval()
: 类似于convertToCircle()
但不取宽高平均值。convertToRect()
: 返回最佳拟合矩形(边界框),并可以选择将其角部圆滑处理。
例如,根据识别结果在Canvas上绘制图形:
switch (recognized?.name) {
case DefaultUnistrokeNames.line:
final (start, end) = recognized!.convertToLine();
canvas.drawLine(start, end, paint);
case DefaultUnistrokeNames.circle:
final (center, radius) = recognized!.convertToCircle();
canvas.drawCircle(center, radius, paint);
case DefaultUnistrokeNames.rectangle:
final rect = recognized!.convertToRect();
if (youWantARoundedRectangle) {
canvas.drawRRect(
RRect.fromRectAndRadius(rect, Radius.circular(10)),
paint,
);
} else {
canvas.drawRect(rect, paint);
}
case DefaultUnistrokeNames.triangle:
case DefaultUnistrokeNames.star:
final polygon = recognized!.convertToCanonicalPolygon();
canvas.drawPoints(PointMode.polygon, polygon, paint);
default:
break;
}
使用自定义单笔画模板
如果你想要识别特定的手势,可以设置referenceUnistrokes
列表以包含自定义的手势模板。这将覆盖默认的模板。
enum MyUnistrokeNames {
circle,
rectangle,
triangle,
leaf,
}
// 定义你的自定义模板
referenceUnistrokes = <Unistroke<MyUnistrokeNames>>[
Unistroke(MyUnistrokeNames.circle, [...]),
Unistroke(MyUnistrokeNames.rectangle, [...]),
Unistroke(MyUnistrokeNames.triangle, [...]),
Unistroke(MyUnistrokeNames.leaf, [...]),
];
// 使用自定义模板进行识别
final recognized = recognizeCustomUnistroke<MyUnistrokeNames>(points);
对于直线这样的特殊情况,确保你的模板只有两个不同的点。
referenceUnistrokes = <Unistroke<MyUnistrokeNames>>[
Unistroke(MyUnistrokeNames.line, [
Offset(0, 0),
Offset(0, 100),
]),
// 其他模板...
];
示例代码
下面是一个完整的示例程序,展示了如何结合Flutter应用使用one_dollar_unistroke_recognizer
插件来创建一个简单的手势识别界面。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '\$1 Unistroke Recognizer Demo',
theme: ThemeData(useMaterial3: true),
home: const GestureRecognizerPage(),
);
}
}
class GestureRecognizerPage extends StatefulWidget {
const GestureRecognizerPage({super.key});
@override
State<GestureRecognizerPage> createState() => _GestureRecognizerPageState();
}
class _GestureRecognizerPageState extends State<GestureRecognizerPage> {
final recognized = ValueNotifier<RecognizedUnistroke?>(null);
Timer? pointDebounce;
void onDraw(List<Offset> points) {
if (pointDebounce == null || !pointDebounce!.isActive) {
pointDebounce = Timer(const Duration(milliseconds: 100), () {
setState(() {
recognized.value = recognizeUnistroke(points);
});
});
}
}
void onDrawEnd(List<Offset> points) {
pointDebounce?.cancel();
pointDebounce = null;
setState(() {
recognized.value = recognizeUnistroke(points);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: ValueListenableBuilder(
valueListenable: recognized,
builder: (context, recognized, child) {
return Text(
recognized == null
? 'Draw below to detect a shape'
: 'Detected "${recognized.name}" with score '
'${recognized.score.toStringAsFixed(2)}',
);
},
),
),
body: Column(
children: [
Expanded(
child: GestureDetector(
onPanUpdate: (details) {
final RenderBox renderBox = context.findRenderObject() as RenderBox;
final Offset localPosition = renderBox.globalToLocal(details.globalPosition);
onDraw([localPosition]);
},
onPanEnd: (details) {
onDrawEnd([]);
},
child: CustomPaint(
size: Size.infinite,
painter: GesturePainter(recognized.value),
),
),
),
],
),
);
}
}
class GesturePainter extends CustomPainter {
final RecognizedUnistroke? recognized;
GesturePainter(this.recognized);
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Colors.black
..strokeWidth = 2
..style = PaintingStyle.stroke;
switch (recognized?.name) {
case DefaultUnistrokeNames.line:
final (start, end) = recognized!.convertToLine();
canvas.drawLine(start, end, paint);
break;
case DefaultUnistrokeNames.circle:
final (center, radius) = recognized!.convertToCircle();
canvas.drawCircle(center, radius, paint);
break;
case DefaultUnistrokeNames.rectangle:
final rect = recognized!.convertToRect();
canvas.drawRect(rect, paint);
break;
case DefaultUnistrokeNames.triangle:
case DefaultUnistrokeNames.star:
final polygon = recognized!.convertToCanonicalPolygon();
canvas.drawPoints(PointMode.polygon, polygon, paint);
break;
default:
break;
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
以上就是关于one_dollar_unistroke_recognizer
插件的详细介绍及示例代码,希望对你有所帮助!
更多关于Flutter手势识别插件one_dollar_unistroke_recognizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter手势识别插件one_dollar_unistroke_recognizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用one_dollar_unistroke_recognizer
插件来识别手势的示例代码。这个插件可以帮助你识别用户绘制的手势,并将它们与预定义的手势进行匹配。
首先,你需要在你的pubspec.yaml
文件中添加这个插件的依赖项:
dependencies:
flutter:
sdk: flutter
one_dollar_unistroke_recognizer: ^最新版本号 # 请替换为插件的最新版本号
然后,运行flutter pub get
来安装依赖项。
接下来,在你的Flutter应用中,你可以按照以下步骤实现手势识别:
- 导入必要的包:
import 'package:flutter/material.dart';
import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart';
- 创建手势识别器并定义预定义手势:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Gesture Recognition'),
),
body: GestureRecognitionScreen(),
),
);
}
}
class GestureRecognitionScreen extends StatefulWidget {
@override
_GestureRecognitionScreenState createState() => _GestureRecognitionScreenState();
}
class _GestureRecognitionScreenState extends State<GestureRecognitionScreen> {
final recognizer = UniStrokeRecognizer();
List<List<Offset>> predefinedGestures = [
[
Offset(50, 50),
Offset(100, 50),
Offset(100, 100),
],
[
Offset(50, 50),
Offset(50, 100),
Offset(100, 100),
],
];
List<Offset> currentGesture = [];
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: GesturePainter(currentGesture, recognizer, predefinedGestures),
size: Size.infinite,
child: GestureDetector(
onPanStart: (details) {
setState(() {
currentGesture.add(details.localPosition);
});
},
onPanUpdate: (details) {
setState(() {
currentGesture.add(details.localPosition);
});
},
onPanEnd: (details) {
setState(() {
final result = recognizer.recognizeGesture(currentGesture, predefinedGestures);
print('Recognized gesture index: ${result?.index}');
currentGesture.clear(); // Clear the current gesture for the next draw
});
},
),
);
}
}
class GesturePainter extends CustomPainter {
final List<Offset> currentGesture;
final UniStrokeRecognizer recognizer;
final List<List<Offset>> predefinedGestures;
GesturePainter(this.currentGesture, this.recognizer, this.predefinedGestures);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.black
..strokeWidth = 4.0
..style = PaintingStyle.stroke;
// Draw predefined gestures
for (var gesture in predefinedGestures) {
Path path = Path();
for (var point in gesture) {
if (path.isEmpty) {
path.moveTo(point.dx, point.dy);
} else {
path.lineTo(point.dx, point.dy);
}
}
canvas.drawPath(path, paint);
}
// Draw current gesture
if (currentGesture.isNotEmpty) {
Path path = Path();
for (var point in currentGesture) {
if (path.isEmpty) {
path.moveTo(point.dx, point.dy);
} else {
path.lineTo(point.dx, point.dy);
}
}
paint.color = Colors.red;
canvas.drawPath(path, paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return oldDelegate != this;
}
}
在这个示例中,我们创建了一个GestureRecognitionScreen
,它使用GestureDetector
来捕获用户的绘制手势。onPanStart
、onPanUpdate
和onPanEnd
回调用于收集用户绘制的点。当用户完成绘制时,onPanEnd
回调会触发手势识别,并打印出识别到的预定义手势的索引。
GesturePainter
类负责在屏幕上绘制预定义的手势和当前的手势。预定义的手势使用黑色绘制,而当前的手势使用红色绘制。
请注意,这只是一个基本示例,你可能需要根据实际需求对代码进行调整和扩展。