在 Flutter 中,缩放手势是一种常见的交互方式,它允许用户通过双指触摸屏幕来改变 UI 元素的大小。这种手势常用于查看图片、地图等场景中。本文接下来将先后介绍如何使用 GestureDetector 和更底层的 ScaleGestureRecognizer 各自实现缩放的代码如何写。
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override 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}); @override State<MyScale> createState() => _MyScaleState(); } class _MyScaleState extends State<MyScale> { double _scale = 1.0; // 堆代码 duidaima.com @override 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 的大小。
const RawGestureDetector({ Key? key, this.child, this.gestures = const <Type, GestureRecognizerFactory>{}, this.behavior, this.excludeFromSemantics = false, this.semantics, }) : super(key: key);ScaleGestureRecognizer 类
ScaleGestureRecognizer 继承自 GestureRecognizer 类,是更底层的手势识别器,用于识别缩放手势。ScaleGestureRecognizer 跟踪与屏幕接触的指针,并计算它们的焦点、指示的缩放级别和旋转。当建立一个焦点时,识别器会调用 onStart回调函数。随着焦点、缩放和旋转的变化,识别器会调用 onUpdate回调函数。当指针不再与屏幕接触时,识别器会调用 onEnd回调函数。
ScaleGestureRecognizer({ Object? debugOwner, // 用于在调试打印中识别手势识别器的对象。 PointerDeviceKind? kind, // 此手势识别器应该处理的设备类型 this.dragStartBehavior = DragStartBehavior.start, // 确定在所有涉及此手势的计算中,用作起点的点 })其中:
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); @override 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); @override State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { final _scaleRecognizer = ScaleGestureRecognizer(); double _scale = 1.0; Offset _panOffset = Offset.zero; @override void initState() { super.initState(); _scaleRecognizer ..onStart = _handleScaleStart ..onUpdate = _handleScaleUpdate ..onEnd = _handleScaleEnd; } @override void dispose() { _scaleRecognizer.dispose(); super.dispose(); } @override 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 组件。