Home > Enterprise >  How to make a button to have some active or inactive effect when a menu is being displayed and hidde
How to make a button to have some active or inactive effect when a menu is being displayed and hidde

Time:07-31

  1. I am using showMenu() function to create and render a menu when onTap() on a certain ListTile widget. So, How to make the ListTile show in an active/inactive state (using some background colour) when the menu is active and vice versa.

  2. PS. I am able to achieve active state when the list tile is clicked using onTap() but unable to achieve the inactive state as I am unable to find a way of reverting the `List Tile background colour because there is no toggle/function when the pop-up menu from show menu is closed.

  3. Please check the below images to get more clarity on the issue.

inactive state inactive state

active and menu open active and menu open

menu closed but colour is still in effect

menu closed but colour is still in effect

    // List to maintain active states (item will be pushed to list on onTap() function)
    List sideOptions = [];

    // function to return color w.r.t if statements
    Color changeBackground(bool isHovered, String sideOption) {
    print(currentRoute);
    if ((isHovered || (currentRoute == "/$sideOption")) ||
        sideOptions.contains(sideOption)) {
      return global_styles.blueShade;
    } else {
      return Colors.transparent;
    }
  }
    // ListTile wrapped in a container
    // OnHoverIcon() is a function i wrote to capture hover events if any
    // ListTile onTap() function


    _buildPopUpMenuButton(
      String title, String iconString, List<PopupMenuEntry> subItems) {
        child: OnHoverIcon(builder: (isHovered) {
            return Container(
              height: 55,
              decoration: BoxDecoration(
                color: changeBackground(isHovered, title),
                borderRadius: const BorderRadius.only(
                  topLeft: Radius.circular(8.0),
                  topRight: Radius.circular(8.0),
                ),
              ),
                  child: ListTile(
                    onTap: () => {
                      sideOptions.add(title),
                      if (!_isDropdownOpen)
                        {_controller.forward(), _isDropdownOpen = true}
                      else
                        {
                          _controller.reverse(),
                          _isDropdownOpen = false,
                        },
                      // _isDropdownOpen = true,
                      showMenu(
                          context: context,
                          position: getSizeandPosition(),
                          items: subItems)
                    },
                    leading: Image.asset(
                      iconString,
                      color: changeIconColors(isHovered, title),
                    ),
                    title: Text(
                      title,
                      style: sideNavItems(isHovered, title),
                    ),
                    trailing: title != "Settings"
                        ? RotationTransition(
                            turns: _rotationAnimation,
                            child: Icon(
                              Icons.keyboard_arrow_up,
                              color: changeIconColors(isHovered, title),
                            ),
                          )
                        : null,
                  ),
            );
          }
        );
      }
}`

CodePudding user response:

showMenu() returns a Future that ends when the menu is popped. So, you can place an await before it and it'll continue to the next line when the menu is popped.

Like this:

void onTap() async {
  // Set the tile as active (changes the color to blue)
  setState(() {
    isActive = true;
  });

  // Show menu and wait for it to pop.
  await showMenu(
    /* ... */
  );

  // Menu is popped. Set the tile as inactive and return to the default color.
  setState(() {
    isActive = false;
  });
}

Edit: It's best to extract the button to its own StatefulWidget so setState() will update just the button instead of the whole page.


If this doesn't work with your code. Maybe place a stateful widget in the menu and use dispose() to detect when it's no longer active and trigger the inactivation method.

  • Related