嵌套列表错误索引,子项可在 Flutter 中折叠

问题描述 投票:0回答:1

我正在尝试实现嵌套侧面导航,但是当某个项目具有子项目时,带有子项目的项目旁边的项目在单击时会显示错误的屏幕。该问题似乎与索引有关。因为下一个项目正在获取之前项目的子项目的索引。我在这上面花了很多时间。但我无法解决它。如果有人知道如何解决它,请告诉我。谢谢。代码如下:

class _MasterScreenState extends State<MasterScreen> {
  int _selectedIndex = 0; // Track the selected index
  late UserModel cUserModel;
  late UserAppInstitutionModel cSelectedUserAppInstitution;
  List<MenuList> currentDestinations = [];
  Set<int> visibleSubMenus = {}; // Track visible submenus by index

  void getUserData(BuildContext context) {
    AuthenticationNotifier authenticationNotifier =
        Provider.of<AuthenticationNotifier>(context, listen: false);
    cUserModel = authenticationNotifier.getUser();
    cSelectedUserAppInstitution =
        authenticationNotifier.getSelectedUserAppInstitution();
  }

  void handleMenuTap(int index) {
    setState(() {
      final menu = currentDestinations[index];

      // If the menu has submenus
      if (menu.subMenus != null && menu.subMenus!.isNotEmpty) {
        // Toggle the visibility of the submenus
        if (visibleSubMenus.contains(index)) {
          visibleSubMenus.remove(index); // Collapse submenu
        } else {
          visibleSubMenus.add(index); // Expand submenu
        }
        // Set selected index to the main menu
        _selectedIndex = index; 
      } else {
        // If it's a main menu item without submenus
        _selectedIndex = index; // Select main menu item
        visibleSubMenus.clear(); // Clear any visible submenus
      }
    });
  }

  void handleSubMenuTap(int mainMenuIndex, int subMenuIndex) {
    setState(() {
      // Calculate the position of the submenu in the list
      int baseIndex = mainMenuIndex + 1; // Start after the main menu
      // Count how many submenus are in the main menu
      int subMenuCount = currentDestinations[mainMenuIndex].subMenus!.length;
      
      // Set selected index based on submenu position
      _selectedIndex = baseIndex + subMenuIndex; // Set selected index based on submenu
    });
  }

  List<SideNavigationBarItem> getSideNavigationBarItem(BuildContext context) {
    currentDestinations = destinations.where((menu) => menu.isVisible).toList();

    List<SideNavigationBarItem> items = [];

    // Iterate over main menu items
    for (int i = 0; i < currentDestinations.length; i++) {
      final menu = currentDestinations[i];

      // Add the main menu item
      items.add(SideNavigationBarItem(
        icon: menu.icon,
        label: menu.label,
      ));

      // Check if the submenu should be visible
      if (visibleSubMenus.contains(i) && menu.subMenus != null) {
        // Add submenu items right after the main menu item
        for (int j = 0; j < menu.subMenus!.length; j++) {
          items.add(SideNavigationBarItem(
            icon: menu.subMenus![j].icon, // Use submenu icon
            label: menu.subMenus![j].label, // Submenu label
          ));
        }
      }
    }

    return items;
  }

  List<Widget> getScreenNavigationBarItem() {
    List<Widget> screens = [];

    // Add the main menu screens and their submenu screens
    for (var menu in currentDestinations) {
      screens.add(menu.screen); // Add main menu screen

      if (menu.subMenus != null) {
        for (var subMenu in menu.subMenus!) {
          screens.add(subMenu.screen); // Add submenu screens
        }
      }
    }

    return screens;
  }

  @override
  Widget build(BuildContext context) {
    getUserData(context);

    return Scaffold(
      body: Row(
        children: [
          // Sidebar for main navigation
          SideNavigationBar(
            expandable: true,
            theme: SideNavigationBarTheme.blue(),
            footer: SideNavigationBarFooter(
              label: Column(
                children: [
                  Text(
                    '${cUserModel.name} ${cUserModel.surname}',
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                  Text(
                    cUserModel.email,
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                  Text(
                    cSelectedUserAppInstitution.roleUserAppInstitution,
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                ],
              ),
            ),
            selectedIndex: _selectedIndex,
            items: getSideNavigationBarItem(context), // Get menu with submenus
            onTap: (index) {
              // Calculate the current index of items
              int currentIndex = 0; // Track the current index across all items (main and submenus)

              for (int i = 0; i < currentDestinations.length; i++) {
                final menu = currentDestinations[i];

                // If this is the selected main menu
                if (currentIndex == index) {
                  // Handle main menu taps
                  handleMenuTap(i);
                  return; // Exit the loop once the right menu is handled
                }

                currentIndex++; // Move to next menu item

                // If this menu has visible submenus, we also need to account for those
                if (visibleSubMenus.contains(i) && menu.subMenus != null) {
                  for (int j = 0; j < menu.subMenus!.length; j++) {
                    if (currentIndex == index) {
                      handleSubMenuTap(i, j); // Handle the tap for the submenu item
                      return;
                    }
                    currentIndex++; // Move to next submenu item
                  }
                }
              }
            },
          ),

          // Expanded area to display the selected content
          Expanded(
            child: LazyIndexedStack(
              index: _selectedIndex, // Use the index to display the selected screen
              children: getScreenNavigationBarItem(), // List of all screens
            ),
          )
        ],
      ),
    );
  }
}

flutter dart flutter-navigation
1个回答
0
投票

可以通过为主菜单项和子菜单项使用单独的索引变量来完成。如:

class _MasterScreenState extends State<MasterScreen> {
  int _selectedMainMenuIndex = 0;  // Track selected main menu index
  int? _selectedSubMenuIndex;      // Track selected submenu
  
  // rest of your code
  
  
  void handleMenuTap(int index) {
  setState(() {
    final menu = currentDestinations[index];

    if (menu.subMenus != null && menu.subMenus!.isNotEmpty) {
      if (visibleSubMenus.contains(index)) {
        visibleSubMenus.remove(index); // Collapse submenu
      } else {
        visibleSubMenus.add(index); // Expand submenu
      }
      _selectedMainMenuIndex = index;
      _selectedSubMenuIndex = null; // Clear any selected submenu
    } else {
      _selectedMainMenuIndex = index;
      _selectedSubMenuIndex = null;
      visibleSubMenus.clear(); // Collapse all submenus
    }
  });
}


  void handleSubMenuTap(int mainMenuIndex, int subMenuIndex) {
    setState(() {
      _selectedMainMenuIndex = mainMenuIndex;
      _selectedSubMenuIndex = subMenuIndex; // Track submenu index
    });
  }

  List<SideNavigationBarItem> getSideNavigationBarItems(BuildContext context) {
    currentDestinations = destinations.where((menu) => menu.isVisible).toList();
    List<SideNavigationBarItem> items = [];

    // Iterate over main menu items
    for (int i = 0; i < currentDestinations.length; i++) {
      final menu = currentDestinations[i];

      // Add main menu item
      items.add(SideNavigationBarItem(
        icon: menu.icon,
        label: menu.label,
      ));

      // Add submenu items if they are visible
      if (visibleSubMenus.contains(i) && menu.subMenus != null) {
        for (int j = 0; j < menu.subMenus!.length; j++) {
          items.add(SideNavigationBarItem(
            icon: menu.subMenus![j].icon,
            label: menu.subMenus![j].label,
          ));
        }
      }
    }

    return items;
  }

  Widget getSelectedScreen() {
    final mainMenu = currentDestinations[_selectedMainMenuIndex];

    if (_selectedSubMenuIndex != null) {
      return mainMenu.subMenus![_selectedSubMenuIndex!].screen;
    }

    return mainMenu.screen;
  }

  @override
  Widget build(BuildContext context) {
     AuthenticationNotifier authenticationNotifier =
        Provider.of<AuthenticationNotifier>(context, listen: true);
      cUserModel = authenticationNotifier.getUser();
      cSelectedUserAppInstitution = authenticationNotifier.getSelectedUserAppInstitution();
    
    // Display a loading state while data is being fetched
    if (cUserModel == null || cSelectedUserAppInstitution == null) {
      return const Center(child: CircularProgressIndicator()); // Show loading spinner until data is available
    }


            footer: SideNavigationBarFooter(
              label: Column(
                children: [
                  Text(
                    '${cUserModel!.name} ${cUserModel!.surname}',  // Safely unwrap nullable values
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                  Text(
                    cUserModel!.email, // Safely unwrap nullable value
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                  Text(
                    cSelectedUserAppInstitution!.roleUserAppInstitution, // Safely unwrap
                    style: Theme.of(context).textTheme.headlineSmall,
                  ),
                ],
              ),
            ),
            selectedIndex: _selectedSubMenuIndex == null
                ? _selectedMainMenuIndex
                : _selectedMainMenuIndex + 1 + _selectedSubMenuIndex!,
            items: getSideNavigationBarItems(context),
            onTap: (index) {
              int currentIndex = 0;

              for (int i = 0; i < currentDestinations.length; i++) {
                final menu = currentDestinations[i];

                if (currentIndex == index) {
                  handleMenuTap(i);
                  return;
                }

                currentIndex++;

                if (visibleSubMenus.contains(i) && menu.subMenus != null) {
                  for (int j = 0; j < menu.subMenus!.length; j++) {
                    if (currentIndex == index) {
                      handleSubMenuTap(i, j);
                      return;
                    }
                    currentIndex++;
                  }
                }
              }
            },
          ),

          // Expanded area to display the selected content
          Expanded(
            child: getSelectedScreen(),
          ),
        ],
      ),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.