KivyMD icon indicating copy to clipboard operation
KivyMD copied to clipboard

NavigationRailItems does not appear on the further screen

Open j4ggr opened this issue 1 year ago • 3 comments

Description of the Bug

I am using two NavigationRails in two different screens. The NavigationRailItems only appear on the first page.

Code

To change page:

  1. Open drawer by clicking menu button
  2. Click on the Item for the page of your choice
  3. Click to the right of the drawer to close it
from kivy.lang import Builder
from kivymd.app import MDApp

KV = '''
<NavigationRailBase@MDNavigationRail>
    anchor: "top"

<MenuButton@MDNavigationRailMenuButton>
    on_release: app.open_menu(self)

<RailItemBase@MDNavigationRailItem>
    icon: "language-%s" % self.text

<PageBase@MDScreen>
    rail_item_1: ""
    rail_item_2: ""
    MDBoxLayout:
        orientation: "vertical"
        MDLabel:
            adaptive_height: True
            text: root.name
        MDBoxLayout:
            NavigationRailBase:
                MenuButton:
                RailItemBase:
                    text: root.rail_item_1
                RailItemBase:
                    text: root.rail_item_2

MDScreen:
    main_sm: main_screen_manager.__self__
    menu: menu.__self__
    MDNavigationLayout:
        ScreenManager:
            id: main_screen_manager
            PageBase:
                name: "First Page"
                rail_item_1: "python"
                rail_item_2: "javascript"
            PageBase:
                name: "Second Page"
                rail_item_1: "cpp"
                rail_item_2: "swift"
    MDNavigationDrawer:
        id: menu
        MDNavigationDrawerMenu:
            MDNavigationDrawerItem:
                text: "First Page"
                icon: "page-first"
                on_release: app.switch_page(self)
            MDNavigationDrawerItem:
                text: "Second Page"
                icon: "page-last"
                on_release: app.switch_page(self)
'''

class Example(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def switch_page(self, drawer_item):
        self.root.main_sm.current = drawer_item.text

    def open_menu(self, *args):
        self.root.menu.set_state("open")

Example().run()

Screenshots

NavigationRailItem_missing_on_second_page

If I change the anchor property of the NavigationRail to "center" or "bottom" (line 6) the NavigationRailItems appear and everything works as expected.

"""
<NavigationRailBase@MDNavigationRail>
    anchor: "center"
"""

NavigationRailItem_no_missing_if_centered

Versions

  • OS: Windows 10
  • Python: 3.10
  • Kivy: 2.1.0
  • KivyMD: 1.0.0.dev0

j4ggr avatar Jul 21 '22 12:07 j4ggr

@j4ggr Your sample code does not demonstrate the problem.

HeaTTheatR avatar Jul 21 '22 12:07 HeaTTheatR

@j4ggr Shorten your example and remove all unnecessary.

HeaTTheatR avatar Jul 21 '22 13:07 HeaTTheatR

Shorten your example and remove all unnecessary.

Done, please excuse the long example before.

Your sample code does not demonstrate the problem.

Yes it does, look at the screenshots. These were made when executing the code above.

j4ggr avatar Jul 21 '22 15:07 j4ggr

How far are you with the analysis?

j4ggr avatar Jan 05 '23 15:01 j4ggr

@j4ggr I haven't looked at this issue...

HeaTTheatR avatar Jan 05 '23 15:01 HeaTTheatR

I investigated the problem further and found that the y-positions of the rail items on the second page are negative.

In the case described above (anchor == 'top' and menu button added), the positions of the RailItems in the method set_pos_panel_items of the MDNavigationRail class become dependent on the y-position of the menu button.

However, at the time this method is called, the y position of the menu button of second page is negative (-3.0).

Now if I update the RailItem positions by calling the set_pos_menu_fab_buttons of the MDNavigationRail class after I switch screens, the items appear on the second page as well. The method requires an interval parameter, although it is not used further within the method. This is probably because the method is called via Clock.schedule_once (an *args would actually suffice here). For this reason I give it a 0. I also adjusted the PageBase class a bit (an ID for the NavigationRail). The updated code looks like this:

from kivy.lang import Builder
from kivymd.app import MDApp

KV = '''
<NavigationRailBase@MDNavigationRail>
    anchor: "top"

<MenuButton@MDNavigationRailMenuButton>
    on_release: app.open_menu(self)

<RailItemBase@MDNavigationRailItem>
    icon: "language-%s" % self.text

<PageBase@MDScreen>
    rail_item_1: ""
    rail_item_2: ""
    MDBoxLayout:
        orientation: "vertical"
        MDLabel:
            adaptive_height: True
            text: root.name
        MDBoxLayout:
            NavigationRailBase:
                id: navigation_rail
                MenuButton:
                RailItemBase:
                    text: root.rail_item_1
                RailItemBase:
                    text: root.rail_item_2

MDScreen:
    main_sm: main_screen_manager.__self__
    menu: menu.__self__
    MDNavigationLayout:
        ScreenManager:
            id: main_screen_manager
            PageBase:
                name: "First Page"
                rail_item_1: "python"
                rail_item_2: "javascript"
            PageBase:
                name: "Second Page"
                rail_item_1: "cpp"
                rail_item_2: "swift"
    MDNavigationDrawer:
        id: menu
        MDNavigationDrawerMenu:
            MDNavigationDrawerItem:
                text: "First Page"
                icon: "page-first"
                on_release: app.switch_page(self)
            MDNavigationDrawerItem:
                text: "Second Page"
                icon: "page-last"
                on_release: app.switch_page(self)
'''

class Example(MDApp):
    def build(self):
        app = Builder.load_string(KV)
        return app
    
    def switch_page(self, drawer_item):
        self.root.main_sm.current = drawer_item.text
        screen = self.root.main_sm.current_screen
        screen.ids['navigation_rail'].set_pos_menu_fab_buttons(0)

    def open_menu(self, *args):
        self.root.menu.set_state("open")

Example().run()

Furthermore, the positions of the items are not updated when the window size changes. For example, if you reduce the height of the window, the items are pushed up outside the window.

j4ggr avatar Jan 26 '23 13:01 j4ggr