flutter overlay_Flutter自绘组件:微信悬浮窗(五)
时间: 2023-07-29 17:05:46 浏览: 158
在上一篇文章中,我们实现了微信悬浮窗的拖动功能。本篇文章将继续讲解如何实现微信悬浮窗的缩放功能。
## 实现思路
微信悬浮窗的缩放功能可以通过手势识别来实现。具体来说,当用户使用两个手指捏合或张开时,我们可以识别出缩放手势,并按照缩放手势的大小来更新悬浮窗的大小。
## 实现步骤
1. 定义缩放手势识别器。
```dart
final scaleGestureDetector = ScaleGestureRecognizer();
```
2. 在 initState 方法中,将缩放手势识别器添加到 GestureDetector 中。
```dart
@override
void initState() {
super.initState();
// 添加缩放手势识别器
scaleGestureDetector
..onScaleStart = _handleScaleStart
..onScaleUpdate = _handleScaleUpdate
..onScaleEnd = _handleScaleEnd;
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onLongPressMoveUpdate: _handleDragUpdate,
onLongPressEnd: _handleDragEnd,
child: CustomPaint(
size: Size(widget.width, widget.height),
painter: _FloatWindowPainter(),
),
// 添加缩放手势识别器
scaleGestureDetector: scaleGestureDetector,
);
}
```
3. 在 _handleScaleUpdate 方法中,根据缩放手势的大小来更新悬浮窗的大小。
```dart
void _handleScaleUpdate(ScaleUpdateDetails details) {
// 计算缩放比例
double scale = details.scale;
if (scale < 1.0) {
// 缩小悬浮窗
widget.width *= scale;
widget.height *= scale;
} else {
// 放大悬浮窗
widget.width += (details.scale - 1.0) * widget.width;
widget.height += (details.scale - 1.0) * widget.height;
}
// 更新悬浮窗位置
_updatePosition();
// 通知父组件更新悬浮窗大小
widget.onSizeChanged(widget.width, widget.height);
// 刷新界面
setState(() {});
}
```
4. 在 _handleScaleEnd 方法中,重置缩放手势识别器。
```dart
void _handleScaleEnd(ScaleEndDetails details) {
// 重置缩放手势识别器
scaleGestureDetector.dispose();
scaleGestureDetector
..onScaleStart = _handleScaleStart
..onScaleUpdate = _handleScaleUpdate
..onScaleEnd = _handleScaleEnd;
}
```
## 完整代码
```dart
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class FloatWindow extends StatefulWidget {
final double x;
final double y;
double width;
double height;
final Widget child;
final Function(double, double) onPositionChanged;
final Function(double, double) onSizeChanged;
FloatWindow({
Key key,
this.x,
this.y,
this.width,
this.height,
this.child,
this.onPositionChanged,
this.onSizeChanged,
}) : super(key: key);
@override
_FloatWindowState createState() => _FloatWindowState();
}
class _FloatWindowState extends State<FloatWindow> {
Offset _offset = Offset.zero;
Offset _position = Offset.zero;
bool _dragging = false;
final scaleGestureDetector = ScaleGestureRecognizer();
@override
void initState() {
super.initState();
// 添加缩放手势识别器
scaleGestureDetector
..onScaleStart = _handleScaleStart
..onScaleUpdate = _handleScaleUpdate
..onScaleEnd = _handleScaleEnd;
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onLongPressMoveUpdate: _handleDragUpdate,
onLongPressEnd: _handleDragEnd,
child: CustomPaint(
size: Size(widget.width, widget.height),
painter: _FloatWindowPainter(),
),
// 添加缩放手势识别器
scaleGestureDetector: scaleGestureDetector,
);
}
@override
void dispose() {
// 释放缩放手势识别器
scaleGestureDetector.dispose();
super.dispose();
}
void _handleScaleStart(ScaleStartDetails details) {
// 记录当前悬浮窗大小
widget.width = context.size.width;
widget.height = context.size.height;
}
void _handleScaleUpdate(ScaleUpdateDetails details) {
// 计算缩放比例
double scale = details.scale;
if (scale < 1.0) {
// 缩小悬浮窗
widget.width *= scale;
widget.height *= scale;
} else {
// 放大悬浮窗
widget.width += (details.scale - 1.0) * widget.width;
widget.height += (details.scale - 1.0) * widget.height;
}
// 更新悬浮窗位置
_updatePosition();
// 通知父组件更新悬浮窗大小
widget.onSizeChanged(widget.width, widget.height);
// 刷新界面
setState(() {});
}
void _handleScaleEnd(ScaleEndDetails details) {
// 重置缩放手势识别器
scaleGestureDetector.dispose();
scaleGestureDetector
..onScaleStart = _handleScaleStart
..onScaleUpdate = _handleScaleUpdate
..onScaleEnd = _handleScaleEnd;
}
void _handleDragUpdate(LongPressMoveUpdateDetails details) {
if (!_dragging) {
_dragging = true;
_offset = Offset(widget.x, widget.y);
}
setState(() {
_position = _offset + details.offset;
widget.onPositionChanged(_position.dx, _position.dy);
});
}
void _handleDragEnd(LongPressEndDetails details) {
_dragging = false;
}
void _updatePosition() {
if (_position.dx + widget.width / 2 > MediaQuery.of(context).size.width) {
_position = Offset(
MediaQuery.of(context).size.width - widget.width / 2,
_position.dy,
);
}
if (_position.dx - widget.width / 2 < 0) {
_position = Offset(widget.width / 2, _position.dy);
}
if (_position.dy + widget.height / 2 > MediaQuery.of(context).size.height) {
_position = Offset(
_position.dx,
MediaQuery.of(context).size.height - widget.height / 2,
);
}
if (_position.dy - widget.height / 2 < 0) {
_position = Offset(_position.dx, widget.height / 2);
}
widget.onPositionChanged(_position.dx, _position.dy);
}
}
class _FloatWindowPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {}
@override
bool shouldRepaint(_FloatWindowPainter oldDelegate) {
return false;
}
}
```
## 总结
本篇文章讲解了如何使用手势识别器来实现微信悬浮窗的缩放功能。通过本篇文章的学习,你已经掌握了手势识别器的使用方法,以及如何在自绘组件中使用手势识别器。在下一篇文章中,我们将讲解如何实现微信悬浮窗的旋转功能。
阅读全文