80 lines
2.0 KiB
Dart
80 lines
2.0 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
|||
|
|
import 'package:flutter/gestures.dart';
|
|||
|
|
|
|||
|
|
/// 遮罩层,icon 区域挖洞可交互
|
|||
|
|
class HoleOverlay extends StatelessWidget {
|
|||
|
|
final Offset iconPosition;
|
|||
|
|
final double iconSize;
|
|||
|
|
final VoidCallback? onTap;
|
|||
|
|
|
|||
|
|
const HoleOverlay({
|
|||
|
|
super.key,
|
|||
|
|
required this.iconPosition,
|
|||
|
|
required this.iconSize,
|
|||
|
|
this.onTap,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return Listener(
|
|||
|
|
behavior: HitTestBehavior.translucent,
|
|||
|
|
onPointerDown: (PointerDownEvent event) {
|
|||
|
|
final RenderBox box = context.findRenderObject() as RenderBox;
|
|||
|
|
final Offset local = box.globalToLocal(event.position);
|
|||
|
|
final iconRect = Rect.fromLTWH(
|
|||
|
|
iconPosition.dx,
|
|||
|
|
iconPosition.dy,
|
|||
|
|
iconSize,
|
|||
|
|
iconSize,
|
|||
|
|
);
|
|||
|
|
if (!iconRect.contains(local)) {
|
|||
|
|
// 遮罩区域,拦截并关闭弹窗
|
|||
|
|
if (onTap != null) {
|
|||
|
|
onTap!();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 如果点在icon区域,什么都不做,事件会传递到下层
|
|||
|
|
},
|
|||
|
|
child: CustomPaint(
|
|||
|
|
size: Size.infinite,
|
|||
|
|
painter: _HolePainter(
|
|||
|
|
iconPosition: iconPosition,
|
|||
|
|
iconSize: iconSize,
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class _HolePainter extends CustomPainter {
|
|||
|
|
final Offset iconPosition;
|
|||
|
|
final double iconSize;
|
|||
|
|
|
|||
|
|
_HolePainter({required this.iconPosition, required this.iconSize});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
void paint(Canvas canvas, Size size) {
|
|||
|
|
final paint = Paint()
|
|||
|
|
..color = Colors.white.withOpacity(0.0)
|
|||
|
|
..blendMode = BlendMode.srcOver;
|
|||
|
|
|
|||
|
|
// 画全屏遮罩
|
|||
|
|
canvas.drawRect(Offset.zero & size, paint);
|
|||
|
|
|
|||
|
|
// 挖洞
|
|||
|
|
final holeRect = Rect.fromLTWH(
|
|||
|
|
iconPosition.dx,
|
|||
|
|
iconPosition.dy,
|
|||
|
|
iconSize,
|
|||
|
|
iconSize,
|
|||
|
|
);
|
|||
|
|
final holePath = Path()..addOval(holeRect);
|
|||
|
|
paint.blendMode = BlendMode.clear;
|
|||
|
|
canvas.drawPath(holePath, paint);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
bool shouldRepaint(covariant _HolePainter oldDelegate) {
|
|||
|
|
return iconPosition != oldDelegate.iconPosition || iconSize != oldDelegate.iconSize;
|
|||
|
|
}
|
|||
|
|
}
|