Kivy - 如何将多个按钮添加到 ModalView 内的 ScrollView?

Kivy - How to add multiple Buttons to ScrollView inside ModalView?

我想用像底部 Sheet 菜单这样的 KivyMD 编写一个移动应用程序。我对 KivyMD Buttom Sheet 的问题是,当我单击按钮打开它时,需要很长时间(取决于菜单长度),因为列表是通过每次按下按钮时调用函数生成的。所以我想为此编写自己的解决方案。 在我的kv文件中我手动添加了20个按钮看看,一切正常。但是我没有在 python 文件中找到循环的方法。 谁能帮我添加 30 多个按钮到 modalview 以便滚动?

这是我的 python 文件:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window


Builder.load_file('mylayout.kv')
Window.size = (350, 700)

class MyLayout(BoxLayout):
    pass

class MainApp(App):

    def build(self):
        return MyLayout()


MainApp().run()

我的 kv 文件:

#:import Factory kivy.factory.Factory

<MyPopup@ModalView>
    auto_dismiss: True
    size_hint: 1, 0.5
    pos_hint: {'x': 0, 'top': 0.5}
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: 48/150,84/150,150/150,1
        Rectangle:
            size: self.size
            pos: self.pos
    ScrollView:
        #do_scroll_x: False
        GridLayout:
            id: container1
            cols: 1
            size_hint: None, None
            size: root.width, 1200
            pos_hint: {'center_x': .5, 'center_y': .5}

            MyButton:
                text: '1'
                on_press:
                    root.dismiss()
                    print(1)
            MyButton:
                text: '2'
                on_press:
                    root.dismiss()
                    print(2)
            MyButton:
                text: '3'
                on_press:
                    root.dismiss()
                    print(3)
            MyButton:
                text: '4'
                on_press:
                    root.dismiss()
                    print(4)
            MyButton:
                text: '5'
                on_press:
                    root.dismiss()
                    print(5)
            MyButton:
                text: '6'
                on_press:
                    root.dismiss()
                    print(6)
            MyButton:
                text: '7'
                on_press:
                    root.dismiss()
                    print(7)
            MyButton:
                text: '8'
                on_press:
                    root.dismiss()
                    print(8)
            MyButton:
                text: '9'
                on_press:
                    root.dismiss()
                    print(9)
            MyButton:
                text: '10'
                on_press:
                    root.dismiss()
                    print(10)
            MyButton:
                text: '11'
                on_press:
                    root.dismiss()
                    print(11)
            MyButton:
                text: '12'
                on_press:
                    root.dismiss()
                    print(12)
            MyButton:
                text: '13'
                on_press:
                    root.dismiss()
                    print(13)
            MyButton:
                text: '14'
                on_press:
                    root.dismiss()
                    print(14)
            MyButton:
                text: '15'
                on_press:
                    root.dismiss()
                    print(15)
            MyButton:
                text: '16'
                on_press:
                    root.dismiss()
                    print(16)
            MyButton:
                text: '17'
                on_press:
                    root.dismiss()
                    print(17)
            MyButton:
                text: '18'
                on_press:
                    root.dismiss()
                    print(18)
            MyButton:
                text: '19'
                on_press:
                    root.dismiss()
                    print(19)
            MyButton:
                text: '20'
                on_press:
                    root.dismiss()
                    print(20)

<MyLayout>
    orientation: 'vertical'
    size: root.width, root.height

    Label:
        size_hint: 1, 0.9
        text: 'main'
        font_size: 24

    Button:
        size_hint: 1, 0.1
        text: 'menu'
        font_size: 24
        on_release: Factory.MyPopup().open()

<MyButton@Button>
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
        Rectangle:
            size: self.size
            pos: self.pos

为了构建填充有 MyButtonsMyPopup,您必须在 python 代码中定义那些 类 或使用 Factory 来创建实例。这是您的 kv 的修改版本:

<MyPopup@ModalView>
    auto_dismiss: True
    size_hint: 1, 0.5
    pos_hint: {'x': 0, 'top': 0.5}
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: 48/150,84/150,150/150,1
        Rectangle:
            size: self.size
            pos: self.pos
    ScrollView:
        #do_scroll_x: False
        GridLayout:
            id: container1
            cols: 1
            size_hint: None, None
            width: root.width
            height: self.minimum_height  # let the GridLayout set its own height as needeed
            pos_hint: {'center_x': .5, 'center_y': .5}
            
<MyLayout>
    orientation: 'vertical'
    size: root.width, root.height

    Label:
        size_hint: 1, 0.9
        text: 'main'
        font_size: 24

    Button:
        size_hint: 1, 0.1
        text: 'menu'
        font_size: 24
        # on_release: Factory.MyPopup().open()
        on_release: app.open_popup()  # call app method to build MyPopup and fill it

<MyButton@Button>
    background_color: 0,0,0,0
    background_normal: ''
    size_hint_y: None
    height: 20
    canvas.before:
        Color:
            rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
        Rectangle:
            size: self.size
            pos: self.pos

请注意,GridLayout 高度设置为 self.minimum_height 以允许任意数量的 MyButton children,并且 MyButton 高度设置为固定值(以便 GridLayout 可以计算最小高度)。此外,kv.

中不再需要导入 Factory

修改后的python代码:

from kivy.app import App
from kivy.factory import Factory
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window

Builder.load_file('mylayout.kv')
Window.size = (350, 700)

class MyLayout(BoxLayout):
    pass

class MainApp(App):

    def build(self):
        return MyLayout()

    def open_popup(self, *args):
        # create the popup (must use Factory since MyPopup is defined in kv)
        self.popup = Factory.MyPopup()

        # fill the GridLayout
        grid = self.popup.ids.container1
        for i in range(60):
            grid.add_widget(Factory.MyButton(text=str(i), on_press=self.myButtPress))

        # open popup
        self.popup.open()

    def myButtPress(self, butt):
        print(butt.text)
        self.popup.dismiss()

MainApp().run()