Enhance navbar item animations
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 45s
Pull Request Pipeline / lint (pull_request) Successful in 47s

This commit is contained in:
2026-05-07 20:39:01 +02:00
parent f0c1ce9881
commit 34a24c9dec

View File

@@ -44,24 +44,49 @@ class _NavbarItemState extends State<NavbarItem>
/// Scale animation for the icon when selected /// Scale animation for the icon when selected
late Animation<double> _scaleAnimation; late Animation<double> _scaleAnimation;
/// Color animation for the icon
late Animation<Color?> _iconColorAnimation;
/// Background color animation for the icon container
late Animation<Color?> _bgColorAnimation;
/// Font size animation for the label
late Animation<double> _fontSizeAnimation;
/// A simple double tween used to lerp between two font weights
late Animation<double> _fontWeightT;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_animationController = AnimationController( _animationController = AnimationController(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
vsync: this, vsync: this,
// Set initial value directly so the visual state matches widget.isSelected
value: widget.isSelected ? 1.0 : 0.0,
); );
_scaleAnimation = Tween<double>(begin: 1.0, end: 1.2).animate( final curved = CurvedAnimation(
CurvedAnimation(
parent: _animationController, parent: _animationController,
curve: Curves.easeInOutBack, curve: Curves.easeOut,
),
); );
if (widget.isSelected) { _scaleAnimation = Tween<double>(begin: 1.0, end: 1.2).animate(curved);
_animationController.forward();
} _iconColorAnimation = ColorTween(
begin: CustomTheme.navBarItemUnselectedColor,
end: CustomTheme.navBarItemSelectedColor,
).animate(curved);
_bgColorAnimation = ColorTween(
begin: Colors.transparent,
end: CustomTheme.primaryColor.withAlpha(50),
).animate(curved);
_fontSizeAnimation = Tween<double>(begin: 11.0, end: 12.0).animate(curved);
// drives font weight interpolation
_fontWeightT = Tween<double>(begin: 0.0, end: 1.0).animate(curved);
} }
// Retrigger animation on selection change // Retrigger animation on selection change
@@ -83,46 +108,44 @@ class _NavbarItemState extends State<NavbarItem>
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0), padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Column( child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
final iconColor = _iconColorAnimation.value!;
final bgColor = _bgColorAnimation.value!;
final fontSize = _fontSizeAnimation.value;
final fontWeight = FontWeight.lerp(
FontWeight.w500,
FontWeight.bold,
_fontWeightT.value,
);
return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
AnimatedContainer( Container(
width: 50, width: 50,
height: 50, height: 50,
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget.isSelected color: bgColor,
? CustomTheme.primaryColor.withAlpha(50)
: Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(15)), borderRadius: const BorderRadius.all(Radius.circular(15)),
), ),
duration: const Duration(milliseconds: 200),
child: ScaleTransition( child: ScaleTransition(
scale: widget.isSelected scale: _scaleAnimation,
? _scaleAnimation child: Icon(widget.icon, color: iconColor, size: 32),
: const AlwaysStoppedAnimation(1.0),
child: Icon(
widget.icon,
color: widget.isSelected
? CustomTheme.navBarItemSelectedColor
: CustomTheme.navBarItemUnselectedColor,
size: 32,
),
), ),
), ),
Text( Text(
widget.label, widget.label,
style: TextStyle( style: TextStyle(
color: widget.isSelected color: iconColor,
? CustomTheme.navBarItemSelectedColor fontSize: fontSize,
: CustomTheme.navBarItemUnselectedColor, fontWeight: fontWeight,
fontSize: widget.isSelected ? 12 : 11,
fontWeight: widget.isSelected
? FontWeight.bold
: FontWeight.w500,
), ),
), ),
], ],
);
},
), ),
), ),
), ),