Files
wushu/lib/views/profile/level/flow-anim.dart
2026-03-30 02:35:31 +08:00

124 lines
2.9 KiB
Dart

import 'dart:math';
import 'package:flutter/material.dart';
import '../../../constants/app_constants.dart';
/// 流动边框装饰器
class FlowingBorderDecoration extends Decoration {
final Animation<double> animation;
final Color color;
final double width;
const FlowingBorderDecoration({
required this.animation,
required this.color,
this.width = 4.0,
});
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return _FlowingBorderPainter(
animation: animation,
color: color,
width: width,
);
}
}
class _FlowingBorderPainter extends BoxPainter {
final Animation<double> animation;
final Color color;
final double width;
_FlowingBorderPainter({
required this.animation,
required this.color,
required this.width,
});
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
final size = configuration.size!;
final rect = offset & size;
final radius = Radius.circular(16);
final paint = Paint()
..color = color
..strokeWidth = width
..style = PaintingStyle.stroke
..shader = LinearGradient(
colors: [color.withAlpha(0), color, color.withAlpha(0)],
stops: const [0.0, 0.5, 1.0],
transform: GradientRotation(2 * pi * animation.value),
).createShader(rect);
canvas.drawRRect(RRect.fromRectAndRadius(rect, radius), paint);
}
}
/// 流动边框容器
class FlowingBorderContainer extends StatefulWidget {
final Widget child;
final Duration duration;
final Color color;
final double width;
final bool autoStart;
const FlowingBorderContainer({
super.key,
required this.child,
this.duration = const Duration(seconds: 10),
this.color = AppConstants.primaryColor,
this.width = 4.0,
this.autoStart = true,
});
@override
State<FlowingBorderContainer> createState() => _FlowingBorderContainerState();
}
class _FlowingBorderContainerState extends State<FlowingBorderContainer>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: widget.duration, vsync: this);
_animation = Tween<double>(
begin: 0,
end: 1,
).animate(CurvedAnimation(parent: _controller, curve: Curves.linear));
if (widget.autoStart) {
_controller.repeat();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
padding: EdgeInsets.all(widget.width),
decoration: FlowingBorderDecoration(
animation: _animation,
color: widget.color,
width: widget.width,
),
child: widget.child,
);
},
);
}
}