Flutter手势防抖插件gesture_debouncer的使用
Flutter手势防抖插件gesture_debouncer的使用
插件介绍
gesture_debouncer
是一个简单的 Flutter 小部件,可以作为防抖器来吸收某些手势,根据冷却时间或未来的状态。
这个小部件在触发与 UI 交互的后端 API 时非常有用。它确保如果用户不小心多次点击,则不会为每次点击都调用后端 API。
通常,在 WebSockets/REST API 使用成功回调的情况下,使用 Completer
将其转换为 Future,并在该小部件中使用。
Completer<List?> completer = Completer<List?>();
Socketio!.emitWithAck("your backend socketio event", params, ack: (data) {
if (data) // 如果数据符合预期
{
if (!completer.isCompleted) {
completer.complete(data);
}
} else {
if (!completer.isCompleted) {
completer.complete(null);
}
}
});
return completer.future;
喜欢我的工作吗?支持我
示例
完整的示例请查看 example/main.dart
。
Widget _getIconWidget(onPressed) {
return IconButton(
icon: Icon(
liked ? FontAwesome.heart : FontAwesome.heart_empty,
),
iconSize: iconSize,
color: liked ? Colors.red : Colors.grey,
onPressed: onPressed,
);
}
// 检测其他手势
Widget _getDoubleClickWidget(onPressed) {
return GestureDetector(
onDoubleTap: onPressed,
child: Icon(
liked2 ? FontAwesome.heart : FontAwesome.heart_empty,
size: iconSize,
color: liked2 ? Colors.green : Colors.grey,
),
);
}
GestureDebouncer(
cooldownAfterExecution: const Duration(seconds: 5),
cooldownBuilder: (BuildContext ctx, _) {
return Stack(
alignment: AlignmentDirectional.center,
children: [
_getIconWidget(() {
if (liked) {
toast("你最近已点赞此内容");
} else {
toast("你最近已取消点赞此内容");
}
}),
IgnorePointer(
// 用于使主图标获得点击事件
child: Icon(
Icons.lock_outline,
color: liked ? Colors.white : Colors.grey,
size: iconSize / 3,
),
),
],
);
},
onError: (e) {
log(e.toString());
},
builder: (BuildContext ctx, Future<void> Function()? onGesture) {
return _getIconWidget(onGesture);
},
onGesture: () async {
setState(() {
liked = !liked;
});
await Future.delayed(const Duration(seconds: 5), () {});
},
)
截图
完整示例代码
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:fluttericon/font_awesome_icons.dart';
import 'package:gesture_debouncer/gesture_debouncer.dart';
import 'package:overlay_support/overlay_support.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return OverlaySupport.global(
toastTheme: ToastThemeData(
background: Colors.indigo,
textColor: Colors.white,
),
child: MaterialApp(
title: '手势防抖器',
theme: ThemeData(
primarySwatch: Colors.indigo,
primaryColor: Colors.indigo,
),
home: const HomePage(),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
[@override](/user/override)
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool liked = false;
bool liked2 = false;
double iconSize = 45;
Widget _getIconWidget(onPressed) {
return IconButton(
icon: Icon(liked ? FontAwesome.heart : FontAwesome.heart_empty),
iconSize: iconSize,
color: liked ? Colors.red : Colors.grey,
onPressed: onPressed,
);
}
Widget _getDoubleClickWidget(onPressed) {
return GestureDetector(
onDoubleTap: onPressed,
child: Icon(
liked2 ? FontAwesome.heart : FontAwesome.heart_empty,
size: iconSize,
color: liked2 ? Colors.green : Colors.grey,
),
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
"手势防抖器",
style: TextStyle(fontSize: 15),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"单击检测器",
style: TextStyle(color: Colors.red),
),
GestureDebouncer(
cooldownAfterExecution: const Duration(seconds: 2),
cooldownBuilder: (BuildContext ctx, _) {
return Stack(
alignment: AlignmentDirectional.center,
children: [
_getIconWidget(() {
if (liked) {
toast("你最近已点赞此内容");
} else {
toast("你最近已取消点赞此内容");
}
}),
IgnorePointer(
// 用于使主图标获得点击事件
child: Icon(
Icons.lock_outline,
color: liked ? Colors.white : Colors.grey,
size: iconSize / 3,
),
),
],
);
},
onError: (e) {
log(e.toString());
},
builder: (BuildContext ctx, Future<void> Function()? onGesture) {
return _getIconWidget(onGesture);
},
onGesture: () async {
setState(() {
liked = !liked;
});
await Future.delayed(const Duration(seconds: 2), () {});
},
),
],
),
const SizedBox(height: 50),
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"双击检测器",
style: TextStyle(color: Colors.green),
),
GestureDebouncer(
cooldownAfterExecution: const Duration(seconds: 2),
cooldownBuilder: (BuildContext ctx, _) {
return Stack(
alignment: AlignmentDirectional.center,
children: [
_getDoubleClickWidget(() {
if (liked2) {
toast("你最近已点赞此内容(双击)");
} else {
toast("你最近已取消点赞此内容(双击)");
}
}),
IgnorePointer(
// 用于使主图标获得点击事件
child: Icon(
Icons.lock_outline,
color: liked2 ? Colors.white : Colors.grey,
size: iconSize / 3,
),
),
],
);
},
onError: (e) {
log(e.toString());
},
builder: (BuildContext ctx, Future<void> Function()? onGesture) {
return _getDoubleClickWidget(onGesture);
},
onGesture: () async {
setState(() {
liked2 = !liked2;
});
await Future.delayed(const Duration(seconds: 2), () {});
},
),
],
),
],
),
);
}
}
更多关于Flutter手势防抖插件gesture_debouncer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter手势防抖插件gesture_debouncer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
gesture_debouncer
是 Flutter 中用于防抖(debounce)手势操作的一个插件。防抖是一种常见的技术,用于防止在短时间内多次触发同一个事件,特别是在处理用户输入、按钮点击或手势操作时非常有用。
1. 安装插件
首先,你需要在 pubspec.yaml
文件中添加 gesture_debouncer
插件的依赖:
dependencies:
flutter:
sdk: flutter
gesture_debouncer: ^1.0.0 # 请根据最新版本号进行替换
然后,运行 flutter pub get
来安装插件。
2. 使用 GestureDebouncer
GestureDebouncer
是一个 Widget,它可以包裹其他需要防抖操作的 Widget,比如 GestureDetector
、InkWell
等。
以下是一个简单的示例,展示如何使用 GestureDebouncer
来防止按钮在短时间内多次点击:
import 'package:flutter/material.dart';
import 'package:gesture_debouncer/gesture_debouncer.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Gesture Debouncer Example'),
),
body: Center(
child: GestureDebouncer(
child: ElevatedButton(
onPressed: () {
print('Button clicked!');
},
child: Text('Click Me'),
),
debounceDuration: Duration(milliseconds: 500), // 设置防抖时间
),
),
),
);
}
}
3. 参数说明
-
debounceDuration: 设置防抖的时间间隔。在这个时间间隔内,如果用户多次触发手势操作,只会执行一次回调。默认值是
Duration(milliseconds: 300)
。 -
child: 需要防抖操作的子 Widget,比如
ElevatedButton
、GestureDetector
等。
4. 解释
在上面的例子中,GestureDebouncer
包裹了 ElevatedButton
,并设置了 debounceDuration
为 500 毫秒。这意味着,如果用户在 500 毫秒内多次点击按钮,只会触发一次 onPressed
回调。
5. 使用场景
GestureDebouncer
适用于以下场景:
- 按钮防抖: 防止用户快速连续点击按钮,导致多次触发事件。
- 手势防抖: 防止用户快速连续进行手势操作,比如双击、长按等。
- 输入防抖: 在处理用户输入时,防止频繁触发回调,比如搜索框的动态搜索。
6. 注意事项
“gesture_debouncer” 插件的版本可能随着时间更新,使用前请确保查看最新的文档和版本信息。
7. 其他实现方式
如果你不想使用第三方插件,也可以自己实现一个简单的防抖逻辑。以下是一个自定义防抖的示例:
import 'package:flutter/material.dart';
class DebouncedButton extends StatefulWidget {
final VoidCallback onPressed;
final Widget child;
final Duration debounceDuration;
DebouncedButton({
required this.onPressed,
required this.child,
this.debounceDuration = const Duration(milliseconds: 500),
});
[@override](/user/override)
_DebouncedButtonState createState() => _DebouncedButtonState();
}
class _DebouncedButtonState extends State<DebouncedButton> {
DateTime? _lastPressed;
[@override](/user/override)
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
final now = DateTime.now();
if (_lastPressed == null ||
now.difference(_lastPressed!) >= widget.debounceDuration) {
_lastPressed = now;
widget.onPressed();
}
},
child: widget.child,
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Custom Debounced Button'),
),
body: Center(
child: DebouncedButton(
onPressed: () {
print('Button clicked!');
},
child: Text('Click Me'),
),
),
),
);
}
}