Skip to content

Instantly share code, notes, and snippets.

@Schwusch
Last active May 21, 2021 02:35
Show Gist options
  • Save Schwusch/f426e015140afdbcef735b25bb77746c to your computer and use it in GitHub Desktop.
Save Schwusch/f426e015140afdbcef735b25bb77746c to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
class BreathingWidget extends StatefulWidget {
final Widget child;
const BreathingWidget({Key key, @required this.child}) : super(key: key);
@override
_BreathingWidgetState createState() => _BreathingWidgetState();
}
class _BreathingWidgetState extends State<BreathingWidget>
with TickerProviderStateMixin {
AnimationController _breathingController;
AnimationController _pulseController;
Animation _animation;
var _breathe = 0.0;
@override
void initState() {
super.initState();
_breathingController =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_pulseController = AnimationController(
vsync: this, duration: Duration(milliseconds: 1500));
_breathingController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_breathingController.reverse();
} else if (status == AnimationStatus.dismissed) {
_breathingController.forward();
}
});
_animation = CurvedAnimation(
parent: _breathingController,
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.fastOutSlowIn.flipped);
_breathingController.addListener(() => setState(() {
if (_breathingController.status == AnimationStatus.forward &&
_animation.value > 0.3) {
if (_pulseController.status != AnimationStatus.forward) {
_pulseController.value = 0.0;
}
_pulseController.forward();
}
_breathe = _animation.value;
}));
_breathingController.forward();
}
@override
void dispose() {
super.dispose();
_breathingController.dispose();
_pulseController.dispose();
}
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: PulsePainter(Curves.easeOut.transform(_pulseController.value)),
child: Transform.scale(
scale: 0.95 + (0.1 * _breathe),
child: widget.child,
),
);
}
}
class PulsePainter extends CustomPainter {
final double scale;
PulsePainter(this.scale);
@override
void paint(Canvas canvas, Size size) {
var rect =
Offset.zero.translate(-(size.width * 2.5), -5 - (size.height * 2.5)) &
(size * 6);
var dynamicColor = Colors.blueGrey.withOpacity(
1.0 - (scale * 0.2 + 0.85).clamp(0.0, 1.0),
);
var gradient = RadialGradient(
colors: [
Colors.transparent.withOpacity(0.0),
dynamicColor,
Colors.transparent.withOpacity(0.0),
dynamicColor,
Colors.transparent.withOpacity(0.0),
],
stops: [
scale,
(scale + 0.05).clamp(0.0, 1.0),
(scale + 0.07).clamp(0.0, 1.0),
(scale + 0.10).clamp(0.0, 1.0),
(scale + 0.2).clamp(0.0, 1.0),
],
);
canvas.drawRect(
rect,
Paint()
..shader = gradient.createShader(rect)
..blendMode = BlendMode.srcATop);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
@Schwusch
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment