| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import 'dart:ui' as ui;
- import 'package:flutter/material.dart';
- import 'package:logging/logging.dart';
- import 'package:puzzleweave/play/board.dart';
- final _log = Logger('overlayer.dart');
- class HintItem {
- final ui.Image finger;
- final Rect srcRect;
- final Rect destRect;
- final CurveTween tween;
- HintItem(this.finger, this.srcRect, this.destRect) : tween = CurveTween(curve: Curves.easeInOut);
- Rect getCurrent(double t) {
- return Rect.lerp(srcRect, destRect, tween.transform(t))!;
- }
- // 动画的前 10% 和后 10% 渐入渐出,中间 80% 完全不透明
- double getOpacity(double t) {
- if (t < 0.1) {
- return t * 10;
- } else if (t >= 0.1 && t <= 0.9) {
- return 1;
- } else {
- return (1 - t) * 10;
- }
- }
- }
- class OverLayer {
- final Board board;
- final TickerProvider tickerProvider;
- OverlayEntry? _overlayEntry;
- bool _isDisposed = false;
- final ValueNotifier<int> _notifier = ValueNotifier(0);
- late AnimationController hintAnimation;
- Listenable get notifiers => Listenable.merge([_notifier, hintAnimation]);
- OverLayer(this.board, this.tickerProvider) {
- hintAnimation = AnimationController(value: 0, vsync: tickerProvider, duration: const Duration(milliseconds: 1200));
- }
- void invalidate() {
- _notifier.value++;
- }
- void setup(BuildContext context) {
- if (_overlayEntry != null) return;
- // 创建并插入 OverlayEntry
- _overlayEntry = OverlayEntry(
- builder: (context) {
- return Positioned.fill(
- // 关键:IgnorePointer 确保手势引导动画不会阻碍底层的 BoardPlay 交互
- child: IgnorePointer(
- child: RepaintBoundary(child: CustomPaint(painter: OverLayerPainter(this))),
- ),
- );
- },
- );
- Overlay.of(context).insert(_overlayEntry!);
- }
- HintItem? _hintItem;
- HintItem? get hintItem => _hintItem;
- void doHint(HintItem hintItem) {
- ///上一次hint没有完成
- if (_isDisposed || _hintItem != null) {
- return;
- }
- _hintItem = hintItem;
- hintAnimation.reset();
- hintAnimation.repeat(); // 重复播放动画
- }
- void stopHint() {
- if (!_isDisposed && _hintItem != null) {
- hintAnimation.stop();
- _hintItem = null;
- invalidate();
- }
- }
- bool get isHinting => _hintItem != null && hintAnimation.isAnimating;
- destroy() {
- _isDisposed = true; // 标记已销毁
- _overlayEntry?.remove();
- _overlayEntry = null;
- hintAnimation.dispose();
- }
- }
- class OverLayerPainter extends CustomPainter {
- final OverLayer overLayer;
- OverLayerPainter(this.overLayer) : super(repaint: overLayer.notifiers);
- @override
- void paint(Canvas canvas, Size size) {
- // canvas.clipRect(Offset.zero & size);
- if (overLayer.hintItem != null) {
- _paintHintItem(canvas, overLayer.hintItem!);
- }
- }
- void _paintHintItem(Canvas canvas, HintItem hintItem) {
- Rect srcRect = Offset.zero & Size(hintItem.finger.width.toDouble(), hintItem.finger.height.toDouble());
- Rect currentRect = hintItem.getCurrent(overLayer.hintAnimation.value);
- // 完善点: 计算并应用透明度
- double opacity = hintItem.getOpacity(overLayer.hintAnimation.value);
- // 创建 Paint,通过 color.withOpacity 控制透明度
- final paint = Paint()
- ..color = Colors.white.withOpacity(opacity)
- ..isAntiAlias = true;
- // 绘制图片
- canvas.drawImageRect(hintItem.finger, srcRect, currentRect, paint);
- }
- @override
- bool shouldRepaint(covariant CustomPainter oldDelegate) {
- return false;
- }
- }
|