如何在 kivymd 中使用 bottom sheet 更改屏幕?

How can I change screen using bottom sheet in kivymd?

我用kivymd做了一个简单的app。但是我无法通过单击 kivymd 中的按钮来更改屏幕。一切都很好。但是当我点击按钮时它也会弹出 toast 但屏幕没有改变。对此会有哪些改变或更好的实施?

app.py

from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
from main_screen_str import helper_string
from kivy.core.window import Window
from kivymd.toast import toast
from kivymd.uix.bottomsheet import MDGridBottomSheet

Window.size = (300, 500)


class MainScreen(Screen):
    pass


class SettingsScreen(Screen):
    pass


class AboutScreen(Screen):
    pass


class MainApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.sm = ScreenManager()
        self.sm.add_widget(MainScreen(name="main_screen"))
        self.sm.add_widget(SettingsScreen(name="settings_screen"))
        self.sm.add_widget(AboutScreen(name="about_screen"))

        self.main_str = Builder.load_string(helper_string)

    def build(self):
        screen = Screen()
        screen.add_widget(self.main_str)
        return screen

    def callback_for_menu_items(self, *args):
        if args[0] == 'Home':
            toast(args[0])
            self.sm.current = "main_screen"

        if args[0] == 'Settings':
            toast(args[0])
            self.sm.current = "settings_screen"

        if args[0] == 'About':
            toast(args[0])
            self.sm.current = "about_screen"

    def show_example_grid_bottom_sheet(self):
        self.bottom_sheet_menu = MDGridBottomSheet()

        data = {
            "Home": "home",
            "Settings": "settings",
            "About": "information-outline",
        }
        for item in data.items():
            self.bottom_sheet_menu.add_item(
                item[0],
                lambda x, y=item[0]: self.callback_for_menu_items(y),
                icon_src=item[1],
            )
        self.bottom_sheet_menu.open()


if __name__ == '__main__':
    MainApp().run()

此构建器字符串用于创建屏幕。 对此有更好的解决方案吗?

生成器字符串

helper_string = """
ScreenManager:
    MainScreen:
    SettingsScreen:
    AboutScreen:

<MainScreen>:
    name: 'main_screen'

    MDIconButton:
        icon: "menu"
        theme_text_color: "Custom"
        text_color: 1,0,0,1
        on_press: app.show_example_grid_bottom_sheet()
  
<SettingsScreen>:
    name: 'settings_screen'
    
<AboutScreen>:
    name: 'about_screen'      
"""

App__init__() 方法中,您正在使用以下行构建 self.sm

    self.sm = ScreenManager()
    self.sm.add_widget(MainScreen(name="main_screen"))
    self.sm.add_widget(SettingsScreen(name="settings_screen"))
    self.sm.add_widget(AboutScreen(name="about_screen"))

但是 self.sm 未用作 GUI 的一部分。因此,您对 self.sm 的更改对您的 GUI 没有影响。接下来的行:

self.main_str = Builder.load_string(helper_string)

基本上与前几行完全相同。

然后在您的 build() 方法中,您将创建一个新的 Screen 并将 self.main_str 添加为该 Screen 的子项。

虽然您可以将 ScreenManager 作为 Screen 的子代,但在您发布的示例中,这似乎没有任何作用。

这是 MainApp 的一部分的修改版本,我认为可以满足您的要求:

class MainApp(MDApp):
    # def __init__(self, **kwargs):
    #     super().__init__(**kwargs)
    #     self.sm = ScreenManager()
    #     self.sm.add_widget(MainScreen(name="main_screen"))
    #     self.sm.add_widget(SettingsScreen(name="settings_screen"))
    #     self.sm.add_widget(AboutScreen(name="about_screen"))
    #
    #     self.main_str = Builder.load_string(helper_string)

    def build(self):
        self.sm = Builder.load_string(helper_string)
        return self.sm
        # screen = Screen()
        # screen.add_widget(self.main_str)
        # return screen

以上代码大大简化了build()方法,去掉了__init__()方法,现在self.sm实际上是GUI的一部分

请注意,当您加载具有 Builder.load_string() 根节点的 kv 字符串时,将创建并返回该根节点。 kv 字符串中的行:

ScreenManager:
    MainScreen:
    SettingsScreen:
    AboutScreen:

导致 ScreenManager 实例连同为其列出的三个子实例一起创建,因此 __init__() 方法中的代码复制了该实例。