Navbar animation verbessert #210

Merged
sneeex merged 2 commits from enhancement/209-navbar-animation-verbessern into development 2026-05-08 16:51:23 +00:00

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.easeOut,
curve: Curves.easeInOutBack,
),
); );
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(
mainAxisSize: MainAxisSize.min, animation: _animationController,
mainAxisAlignment: MainAxisAlignment.center, builder: (context, child) {
children: [ final iconColor = _iconColorAnimation.value!;
AnimatedContainer( final bgColor = _bgColorAnimation.value!;
width: 50, final fontSize = _fontSizeAnimation.value;
height: 50, final fontWeight = FontWeight.lerp(
decoration: BoxDecoration( FontWeight.w500,
color: widget.isSelected FontWeight.bold,
? CustomTheme.primaryColor.withAlpha(50) _fontWeightT.value,
: Colors.transparent, );
borderRadius: const BorderRadius.all(Radius.circular(15)), return Column(
), mainAxisSize: MainAxisSize.min,
duration: const Duration(milliseconds: 200), mainAxisAlignment: MainAxisAlignment.center,
child: ScaleTransition( children: [
scale: widget.isSelected Container(
? _scaleAnimation width: 50,
: const AlwaysStoppedAnimation(1.0), height: 50,
child: Icon( decoration: BoxDecoration(
widget.icon, color: bgColor,
color: widget.isSelected borderRadius: const BorderRadius.all(Radius.circular(15)),
? CustomTheme.navBarItemSelectedColor ),
: CustomTheme.navBarItemUnselectedColor, child: ScaleTransition(
size: 32, scale: _scaleAnimation,
child: Icon(widget.icon, color: iconColor, size: 32),
),
), ),
), Text(
), widget.label,
Text( style: TextStyle(
widget.label, color: iconColor,
style: TextStyle( fontSize: fontSize,
color: widget.isSelected fontWeight: fontWeight,
? CustomTheme.navBarItemSelectedColor ),
: CustomTheme.navBarItemUnselectedColor, ),
fontSize: widget.isSelected ? 12 : 11, ],
fontWeight: widget.isSelected );
? FontWeight.bold },
: FontWeight.w500,
),
),
],
), ),
), ),
), ),