88 lines
2.1 KiB
Dart
88 lines
2.1 KiB
Dart
import 'dart:math' as math;
|
|
import 'package:flutter/material.dart';
|
|
|
|
class CozyWave extends StatefulWidget {
|
|
final double percentage;
|
|
final Color color;
|
|
|
|
const CozyWave({super.key, required this.percentage, required this.color});
|
|
|
|
@override
|
|
State<CozyWave> createState() => _CozyWaveState();
|
|
}
|
|
|
|
class _CozyWaveState extends State<CozyWave>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(seconds: 3),
|
|
)..repeat();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _controller,
|
|
builder: (context, child) {
|
|
return ClipPath(
|
|
clipper: WaveClipper(_controller.value, widget.percentage),
|
|
child: Container(
|
|
height: double.infinity,
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [widget.color, widget.color.withOpacity(0.8)],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class WaveClipper extends CustomClipper<Path> {
|
|
final double animationValue;
|
|
final double percentage;
|
|
|
|
WaveClipper(this.animationValue, this.percentage);
|
|
|
|
@override
|
|
Path getClip(Size size) {
|
|
final path = Path();
|
|
final double baseHeight = size.height * (1 - percentage);
|
|
path.moveTo(0, baseHeight);
|
|
for (double i = 0; i <= size.width; i++) {
|
|
path.lineTo(
|
|
i,
|
|
baseHeight +
|
|
math.sin(
|
|
(i / size.width * 2 * math.pi) +
|
|
(animationValue * 2 * math.pi),
|
|
) *
|
|
8,
|
|
);
|
|
}
|
|
path.lineTo(size.width, size.height);
|
|
path.lineTo(0, size.height);
|
|
path.close();
|
|
return path;
|
|
}
|
|
|
|
@override
|
|
bool shouldReclip(WaveClipper oldClipper) => true;
|
|
}
|