Flutter多点长按手势识别插件multi_long_press_gesture_recognizer的使用
Flutter多点长按手势识别插件multi_long_press_gesture_recognizer的使用
描述
multi_long_press_gesture_recognizer
是一个Flutter插件,能够识别用户在相同位置长时间按下多个指针的情况。它与Flutter自带的 LongPressGestureRecognizer
类似,但支持多点触控。
功能特性
- 支持多点长按检测:可以识别多个指针同时长按。
- 可配置的滑动容差:可以在手势识别前和识别后配置滑动容差。
- 可配置的长按持续时间:可以设置触发长按事件所需的最短时间。
完整示例Demo
以下是一个完整的示例代码,展示了如何使用 multi_long_press_gesture_recognizer
插件来实现多点长按手势识别。
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:multi_long_press_gesture_recognizer/multi_long_press_gesture_recognizer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter MLP Demo",
theme: ThemeData(),
darkTheme: ThemeData.dark(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Queue<MapEntry<Type?, int>> _lastStates = Queue();
int _counter = 0;
int maxSize = 10;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _addState(Object? details) {
var entry = (_lastStates.lastOrNull?.key == details?.runtimeType
? _lastStates.removeLast()
: null) ??
MapEntry(details?.runtimeType, 0);
_lastStates.addWithLimit(MapEntry(entry.key, entry.value + 1), maxSize);
}
[@override](/user/override)
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
MultiLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers<
MultiLongPressGestureRecognizer>(
() => MultiLongPressGestureRecognizer(
duration: const Duration(milliseconds: 500), // 设置长按持续时间为500毫秒
preAcceptSlopTolerance: 18.0, // 设置手势识别前的滑动容差
pointerThreshold: 2, // 设置触发长按事件所需的最小指针数量
),
(instance) {
instance
..onMultiLongPressDown = (details) {
setState(() => _addState(details)); // 处理多点长按按下事件
}
..onMultiLongPress = (details) {
HapticFeedback.vibrate(); // 触发震动反馈
_addState(details); // 记录状态
_incrementCounter(); // 增加计数器
}
..onMultiLongPressCancel = () {
setState(() => _addState(null)); // 处理多点长按取消事件
}
..onMultiLongPressMoveUpdate = (details) {
setState(() => _addState(details)); // 处理多点长按移动事件
}
..onMultiLongPressUp = (details) {
setState(() => _addState(details)); // 处理多点长按抬起事件
};
},
),
},
child: Scaffold(
appBar: AppBar(
title: const Text("Flutter Multi-Long-Press Demo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildStatesLog(context), // 构建状态日志
_buildLegend(context), // 构建图例
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Last recognizer state:"),
Text(
_lastStates.lastOrNull != null
? _getName(_lastStates.last.key)
: "-",
style: Theme.of(context).textTheme.headlineMedium,
),
const Flexible(child: SizedBox(height: 50)),
const Text(
"You have triggered the gesture this many times:",
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(25)),
border: Border.all(
color: Theme.of(context).colorScheme.onSurface,
width: 5.0,
),
color: Theme.of(context).colorScheme.surfaceBright,
),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: ClipRRect(
borderRadius:
const BorderRadius.all(Radius.circular(20)),
child: InteractiveViewer(
boundaryMargin: const EdgeInsets.all(500.0),
minScale: 0.5,
maxScale: 2.0,
child: Container(
height: 300,
width: 300,
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.onSurface,
width: 4.0,
),
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment(0.8, 1),
colors: [
Color(0xff1f005c),
Color(0xff5b0060),
Color(0xff870160),
Color(0xffac255e),
Color(0xffca485c),
Color(0xffe16b5c),
Color(0xfff39060),
Color(0xffffb56b),
],
tileMode: TileMode.mirror,
),
),
child: const Center(
child: Text(
"Drag Me",
style: TextStyle(
fontSize: 28,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
),
),
),
),
),
),
)
],
),
),
),
);
}
Widget _buildStatesLog(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
width: 2.0,
color: Theme.of(context).colorScheme.onSurface,
),
borderRadius: const BorderRadius.all(Radius.circular(25)),
),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
const double circleDiameter = 30.0;
const double circlePadding = 2.0;
const double circleSize = circleDiameter + (circlePadding * 2);
var newMaxSize = constraints.maxWidth ~/ circleSize;
if (newMaxSize != maxSize) {
_lastStates.clearWithLimit(newMaxSize);
}
maxSize = newMaxSize;
return ConstrainedBox(
constraints: const BoxConstraints.tightFor(height: circleSize),
child: Row(
children: [
for (MapEntry<Type?, int> state in _lastStates.take(maxSize))
_buildStateIcon(
circlePadding,
circleDiameter,
3.0,
state.key,
value: state.value == 1 ? null : state.value.toString(),
),
],
),
);
}),
),
),
);
}
Widget _buildLegend(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildStateDescription(MultiLongPressDownDetails),
_buildStateDescription(MultiLongPressDetails),
_buildStateDescription(MultiLongPressMoveUpdateDetails),
_buildStateDescription(MultiLongPressUpDetails),
_buildStateDescription(null),
],
);
}
Widget _buildStateDescription(Type? state, {TextStyle? textStyle}) {
textStyle ??= const TextStyle(fontWeight: FontWeight.bold);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildStateIcon(0, 14.0, 2.0, state),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Text("=", style: textStyle),
),
Text(_getName(state), style: textStyle),
],
);
}
Widget _buildStateIcon(
double circlePadding,
double circleDiameter,
double borderWidth,
Type? state, {
String? value,
}) {
return Padding(
padding: EdgeInsets.all(circlePadding),
child: Container(
width: circleDiameter,
height: circleDiameter,
decoration: BoxDecoration(
color: _getColor(state),
border: Border.all(
color: _getBorderColor(state),
width: borderWidth,
),
shape: BoxShape.circle,
),
child: value != null
? Center(
child: Text(
value,
style: TextStyle(
fontSize: value.length > 2 ? 8.0 : 14.0,
fontWeight: FontWeight.bold,
),
),
)
: null,
),
);
}
Color? _getColor(Type? state) {
switch (state) {
case MultiLongPressDetails:
return Colors.green;
case MultiLongPressDownDetails:
return Colors.blue;
case MultiLongPressMoveUpdateDetails:
return null;
case MultiLongPressUpDetails:
return null;
case null:
return null;
default:
return null;
}
}
Color _getBorderColor(Type? state) {
switch (state) {
case MultiLongPressDetails:
return Colors.green;
case MultiLongPressDownDetails:
return Colors.blue;
case MultiLongPressMoveUpdateDetails:
return Colors.yellow.shade600;
case MultiLongPressUpDetails:
return Colors.orange;
case null:
return Colors.grey;
default:
return Colors.purple;
}
}
String _getName(Type? state) {
switch (state) {
case MultiLongPressDetails:
return "Press";
case MultiLongPressDownDetails:
return "Down";
case MultiLongPressMoveUpdateDetails:
return "Move";
case MultiLongPressUpDetails:
return "Up";
case null:
return "Cancel";
default:
throw UnsupportedError("Unknown state: $state");
}
}
}
extension QueueExt<T> on Queue<T> {
void addWithLimit(T element, int limit) {
while (length >= limit) {
removeFirst();
}
add(element);
}
void clearWithLimit(int limit) {
while (length >= limit) {
removeFirst();
}
}
}
更多关于Flutter多点长按手势识别插件multi_long_press_gesture_recognizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter多点长按手势识别插件multi_long_press_gesture_recognizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用multi_long_press_gesture_recognizer
插件的示例代码。这个插件允许你识别多点长按手势。首先,你需要确保已经添加了该插件到你的pubspec.yaml
文件中:
dependencies:
flutter:
sdk: flutter
multi_long_press_gesture_recognizer: ^最新版本号 # 请替换为实际的最新版本号
然后,运行flutter pub get
来安装插件。
以下是一个简单的示例,展示了如何使用multi_long_press_gesture_recognizer
来识别多点长按手势:
import 'package:flutter/material.dart';
import 'package:multi_long_press_gesture_recognizer/multi_long_press_gesture_recognizer.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Multi Long Press Gesture Recognizer Demo'),
),
body: Center(
child: MultiLongPressGestureDetector(
onMultiLongPressStart: (details) {
// 当多点长按开始时触发
print('Multi Long Press Started at: ${details.globalPosition}');
// details.pointers 包含所有参与长按的指针信息
details.pointers.forEach((pointer) {
print('Pointer: ${pointer.device} at position: ${pointer.position}');
});
},
onMultiLongPressUpdate: (details) {
// 当多点长按更新(即手指移动)时触发
print('Multi Long Press Updated at: ${details.globalPosition}');
details.pointers.forEach((pointer) {
print('Pointer: ${pointer.device} at position: ${pointer.position}');
});
},
onMultiLongPressEnd: (details) {
// 当多点长按结束时触发
print('Multi Long Press Ended at: ${details.globalPosition}');
details.pointers.forEach((pointer) {
print('Pointer: ${pointer.device} at position: ${pointer.position}');
});
},
child: Container(
width: 300,
height: 300,
color: Colors.blue.withOpacity(0.5),
child: Center(
child: Text(
'Long Press Multiple Points Here',
style: TextStyle(color: Colors.white),
),
),
),
),
),
),
);
}
}
在这个示例中,我们创建了一个MultiLongPressGestureDetector
,它监听一个容器内的多点长按手势。当多点长按开始时,onMultiLongPressStart
回调会被触发,并打印出所有参与长按的指针信息。同样,当多点长按更新(即手指移动)和结束时,onMultiLongPressUpdate
和onMultiLongPressEnd
回调也会被触发,并打印出相应的信息。
这个插件为多点长按手势提供了细粒度的控制,允许你处理每个指针的位置和状态,非常适合需要复杂手势识别的应用场景。