89 lines
2.6 KiB
Dart
89 lines
2.6 KiB
Dart
// Author: fruit.com.cn
|
|
// 职责:绘制收藏点赞周围的紧凑双向短线,无圆环或阴影,不参与手势。
|
|
import 'dart:math' as math;
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
const int _rayCount = 8;
|
|
const double _startProgress = 0.1;
|
|
const double _radiusStart = 0.34;
|
|
const double _radiusTravel = 0.14;
|
|
const double _rayLength = 0.07;
|
|
const double _strokeFraction = 0.025;
|
|
const double _rayAlpha = 0.65;
|
|
const double _fullCircle = math.pi * 2;
|
|
const double _rayRotation = math.pi / _rayCount;
|
|
|
|
/// 收藏/点赞的装饰反馈:选中外扩,取消收束。
|
|
class RailTapBurst extends StatelessWidget {
|
|
/// [progress] 来自按钮的点击动画,不创建独立计时器。
|
|
const RailTapBurst({
|
|
super.key,
|
|
required this.progress,
|
|
required this.color,
|
|
required this.contracting,
|
|
});
|
|
|
|
final double progress;
|
|
final Color color;
|
|
final bool contracting;
|
|
|
|
@override
|
|
Widget build(BuildContext context) => IgnorePointer(
|
|
child: CustomPaint(
|
|
painter: _RailBurstPainter(
|
|
progress: progress,
|
|
color: color,
|
|
contracting: contracting,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
class _RailBurstPainter extends CustomPainter {
|
|
const _RailBurstPainter({
|
|
required this.progress,
|
|
required this.color,
|
|
required this.contracting,
|
|
});
|
|
|
|
final double progress;
|
|
final Color color;
|
|
final bool contracting;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final phase = ((progress - _startProgress) / (1 - _startProgress)).clamp(
|
|
0.0,
|
|
1.0,
|
|
);
|
|
if (phase == 0 || phase == 1) return;
|
|
final eased = Curves.easeOutCubic.transform(phase);
|
|
final travel = contracting ? 1 - eased : eased;
|
|
final base = size.shortestSide;
|
|
final radius = base * (_radiusStart + _radiusTravel * travel);
|
|
final alpha = math.sin(math.pi * phase);
|
|
final paint = Paint()
|
|
..style = PaintingStyle.stroke
|
|
..strokeCap = StrokeCap.round
|
|
..strokeWidth = base * _strokeFraction
|
|
..color = color.withValues(alpha: alpha * _rayAlpha);
|
|
final center = size.center(Offset.zero);
|
|
final length = base * _rayLength * (1 - phase);
|
|
for (var index = 0; index < _rayCount; index++) {
|
|
final angle = _fullCircle * index / _rayCount + _rayRotation;
|
|
canvas.drawLine(
|
|
center + Offset.fromDirection(angle, radius),
|
|
center + Offset.fromDirection(angle, radius + length),
|
|
paint,
|
|
);
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant _RailBurstPainter oldDelegate) =>
|
|
oldDelegate.progress != progress ||
|
|
oldDelegate.color != color ||
|
|
oldDelegate.contracting != contracting;
|
|
}
|