Files
ai_chat_assistant/lib/widgets/_hole_overlay.dart

80 lines
2.0 KiB
Dart
Raw Normal View History

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;
}
}