skip to Main Content

I created a full custom side menu.
On mobile, I would like the menu to fully collapse.

So, I created the following structure :

AnimatedContainer
    Column
        Image          
        SizedBox,
        Padding
            MenuItem

where MenuItem widget is as bellow :

Padding(
      padding: const EdgeInsets.only(bottom:16),
      child: MouseRegion(
        cursor: SystemMouseCursors.click,
        child: GestureDetector(
          onTap: () {
            NavigatorKeys.navigatorKey.currentState?.pushNamed(route);
            // Callback call
            if(onClicked != null){
              onClicked!();
            }
          },
          child: Row(
            children: [
              Icon(
                icon,
                size: 48,
                color: theme.colorScheme.onPrimaryContainer,
              ),
              Expanded(
                child: AnimatedOpacity(
                  opacity: textOpacity,
                  duration: animDuration,
                  curve: Curves.easeInOut,
                  child: Padding(
                    padding: const EdgeInsets.only(left:16),
                    child: Text(
                      label,
                      overflow: TextOverflow.ellipsis,
                      style: style,
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );

With this Layout, the text is collapsing perfectly.
But an overflow error is thrown because of the Icons.

GIF of the collapsing animation

enter image description here

To avoid the overflow, I tried to wrap the Icon Widget with Flexible.
But now we will have two Flex children for the Row, dividing by two the available space for each Widget.
We want the Icon to be width fixed and the text to take all the space remaining.

An idea to fix this behavior ?
Thank you.

2

Answers


  1. Please check by wrapping the icons as below.

    LayoutBuilder(builder: (context, constraint) {
        return Icon(Icons.access_alarms, size: constraint.biggest.height);
    }),
    

    Where constraint is 48 as you mentioned above.

    Login or Signup to reply.
  2. You can use the AnimatedBuilder Widget. Official docs are here for reference: https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html

    You can use the below code as reference for your drawer and to get some idea about how to implement AnimatedBuilder.

    import 'package:flutter/material.dart';
    
    class Drawer extends StatefulWidget {
      const Drawer({super.key});
    
      @override
      State<Drawer> createState() => _DrawerState();
    }
    
    class _DrawerState extends State<Drawer> with SingleTickerProviderStateMixin {
      late final AnimationController animationController;
      Animation<double>? slideAnimation;
      late final Animation<double> iconSizeAnimation;
    
      @override
      void initState() {
        animationController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 800),
        );
    
        iconSizeAnimation =
            Tween<double>(begin: 0, end: 48).animate(animationController);
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        final screenSize = MediaQuery.of(context).size;
    
        // initialising here instead on init state as I need media query, you can add custom curves using curved animation
        slideAnimation ??= Tween<double>(
          begin: 0,
          end: screenSize.width / 2,
        ).animate(animationController);
    
        // Instead of using Animated container use Animated builder on a container which will execute using your animationController and pass the values you want to change as tween animations
        return AnimatedBuilder(
          animation: animationController,
          builder: (context, child) {
            return SizedBox(
              // Animated width for slide
              width: slideAnimation!.value,
              height: screenSize.height,
              // Here you can specify how widgets in your row should be aligned
              child: Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Icon(
                    // Your own icon
                    Icons.add,
                    // we use .value to get current animation value according to the animation controller
                    size: iconSizeAnimation.value,
                  ),
                  const Expanded(
                    child: Text('some text'),
                  ),
                ],
              ),
            );
          },
        );
      }
    }
    

    You can modify your code taking this as reference.

    Simply call animationController.forward() and animationController.reverse() to run the animation.

    This should solve your problem.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search