作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :[email protected]
本文地址:https://blog.csdn.net/qq_28550263/article/details/134485138
在 Flutter 中,缩放手势是一种常见的交互方式,它允许用户通过双指触摸屏幕来改变 UI 元素的大小。这种手势常用于查看图片、地图等场景中。本文接下来将先后介绍如何使用 GestureDetector 和更底层的 ScaleGestureRecognizer 各自实现缩放的代码如何写。
在 Flutter 中,缩放手势的识别和处理主要依赖于 GestureDetector 组件。这个组件可以识别各种手势,包括缩放手势。
GestureDetector 组件有多个属性用于处理缩放,主要包括:
属性 | 描述 |
---|---|
onScaleStart | 当缩放手势开始时调用 |
onScaleUpdate | 当缩放手势更新时调用 |
onScaleEnd | 当缩放手势结束时调用 |
例如:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('GestureDetector Example'),
),
body: const Center(
child: MyScale(),
),
),
);
}
}
class MyScale extends StatefulWidget {
const MyScale({super.key});
State<MyScale> createState() => _MyScaleState();
}
class _MyScaleState extends State<MyScale> {
double _scale = 1.0;
Widget build(BuildContext context) {
return GestureDetector(
onScaleStart: (ScaleStartDetails details) {
print('缩放开始');
},
onScaleUpdate: (ScaleUpdateDetails details) {
setState(() {
_scale = details.scale;
});
print('缩放更新,当前缩放值:$_scale');
},
onScaleEnd: (ScaleEndDetails details) {
print('缩放结束');
},
child: Transform.scale(
scale: _scale,
child: const FlutterLogo(size: 200),
),
);
}
}
上面的代码中,我们使用 GestureDetector 组件来识别缩放手势,并在 onScaleUpdate 回调函数中更新 _scale 变量的值。然后,我们使用 Transform.scale 组件来根据 _scale 的值来改变 Flutter Logo 的大小。其效果如下:
使用 RawGestureDetector 和 ScaleGestureRecognizer 也可以实现缩放手势。在大多数情况下,GestureDetector 组件已经足够用于处理缩放手势。然而,在一些的场景中我们可能需要更多的控制,这时就可以使用 ScaleGestureRecognizer 类。
const RawGestureDetector({
Key? key,
this.child,
this.gestures = const <Type, GestureRecognizerFactory>{},
this.behavior,
this.excludeFromSemantics = false,
this.semantics,
}) : super(key: key);
ScaleGestureRecognizer 继承自 GestureRecognizer 类,是更底层的手势识别器,用于识别缩放手势。
ScaleGestureRecognizer 跟踪与屏幕接触的指针,并计算它们的焦点、指示的缩放级别和旋转。当建立一个焦点时,识别器会调用 onStart
回调函数。随着焦点、缩放和旋转的变化,识别器会调用 onUpdate
回调函数。当指针不再与屏幕接触时,识别器会调用 onEnd
回调函数。
以下是 ScaleGestureRecognizer 的一些重要属性和方法:
onStart
:当与屏幕接触的指针建立了焦点和初始缩放级别为1.0时调用。onUpdate
:当与屏幕接触的指针指示了新的焦点和/或缩放时调用。onEnd
:当指针不再与屏幕接触时调用。addPointer
:注册可能与此手势检测器相关的新指针。addAllowedPointer
:注册已经被此手势识别器允许的新指针。dispose
:释放由对象使用的任何资源。ScaleGestureRecognizer 类的造函数如下:
ScaleGestureRecognizer({
Object? debugOwner, // 用于在调试打印中识别手势识别器的对象。
PointerDeviceKind? kind, // 此手势识别器应该处理的设备类型
this.dragStartBehavior = DragStartBehavior.start, // 确定在所有涉及此手势的计算中,用作起点的点
})
其中:
kind
:此手势识别器应该处理的设备类型。例如,如果 kind 设置为 PointerDeviceKind.mouse,那么这个手势识别器只会识别鼠标的手势。dragStartBehavior
:确定在所有涉及此手势的计算中,用作起点的点。默认值为 DragStartBehavior.start。下面是一个使用 RawGestureDetector 和 ScaleGestureRecognizer 来识别和处理缩放和拖动手势的示例:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('GestureDetector Example'),
),
body: const Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final _scaleRecognizer = ScaleGestureRecognizer();
double _scale = 1.0;
Offset _panOffset = Offset.zero;
void initState() {
super.initState();
_scaleRecognizer
..onStart = _handleScaleStart
..onUpdate = _handleScaleUpdate
..onEnd = _handleScaleEnd;
}
void dispose() {
_scaleRecognizer.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
ScaleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<ScaleGestureRecognizer>(
() => _scaleRecognizer,
(ScaleGestureRecognizer instance) {},
),
},
child: Transform.scale(
scale: _scale,
child: Transform.translate(
offset: _panOffset,
child: const FlutterLogo(size: 200),
),
),
);
}
void _handleScaleStart(ScaleStartDetails details) {
print('缩放开始');
}
void _handleScaleUpdate(ScaleUpdateDetails details) {
setState(() {
_scale = details.scale;
_panOffset = details.localFocalPoint;
});
print('缩放更新,当前缩放值:$_scale');
print('拖动更新,当前偏移值:$_panOffset');
}
void _handleScaleEnd(ScaleEndDetails details) {
print('缩放结束');
}
}
需要注意的是,使用 RawGestureDetector 比使用 GestureDetector 组件更复杂,需要手动管理手势的生命周期,包括创建、更新和释放手势。因此,除非你需要处理复杂的手势,否则通常推荐使用 GestureDetector 组件。