【问题标题】:Centering a Layout within ScrollView. Kivy/KivyMD在 ScrollView 中居中布局。基维/基维MD
【发布时间】:2020-09-17 17:08:41
【问题描述】:

我正在尝试在 Kivy/KivyMD 中创建响应式、居中和可滚动的布局。到目前为止,我已经开发了两种布局,一种将 BoxLayout 置于 FloatLayout 的中心,并且可以很好地调整大小,但它不会滚动。 我还开发了一个布局,它是 ScrollView 中的 GridLayout,它可以很好地调整大小,但是在大窗口大小时,它不能正确地将 GridLayout 居中。

我尝试将 BoxLayout 放在 ScrollView 中的 FloatLayout 中,它可以很好地调整大小但滚动条不起作用。

到目前为止,我无法将居中的可调整大小的布局组合到正常工作的滚动视图中。我应该如何做到这一点?

这是我的滚动视图示例:

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout


LIPSUM = """Very long lipsum..."""


Builder.load_string("""
<ExampleScroll@ScrollView>:
    do_scroll_x: False

    bar_width: 10
    bar_color: app.theme_cls.primary_color
    bar_color_acrive: app.theme_cls.accent_color
    effect_cls: "DampedScrollEffect"
    scroll_type: ['bars']

    GridLayout:  # If FloatLayout and BoxLayout, doesn't scroll!
        cols: 1
        size_hint_y: None
        height: self.minimum_height

        size_hint_x: .75
        size_hint_max_x: dp(800)
        size_hint_min_x: min(dp(400), root.width)

        pos_hint: {'center_x': .5}  # Fails to center layout
        padding: 0, dp(16), 0, 0

        MDLabel:
            text: app.label_text + app.label_text
            halign: 'justify'
            padding: dp(16), dp(16)
            markup: True
            font_style: 'Body1'
            theme_text_color: 'Primary'
            size_hint_y: None
            height: self.texture_size[1]

            text_size: self.size
        MDLabel:
            text: app.label_text + app.label_text
            halign: 'justify'
            padding: dp(16), dp(16)
            markup: True
            font_style: 'Body1'
            theme_text_color: 'Primary'
            size_hint_y: None
            height: self.texture_size[1]

            text_size: self.size
        Widget
""")


class ExampleScroll(ScrollView):
    pass


class Example(MDApp):
    title = "Dialogs"
    label_text = LIPSUM

    def build(self):
        return ExampleScroll()


Example().run()

这是我的居中示例:

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout


LIPSUM = """Very long lipsum..."""


Builder.load_string("""
<ExampleCenter@FloatLayout>:
    BoxLayout:
        orientation: 'vertical'

        # Gives the BoxLayout a max and min width that is responsive
        size_hint_x: .75
        size_hint_max_x: dp(800)
        size_hint_min_x: min(dp(400), root.width)

        # Centers the BoxLayout horizontally responsively
        pos_hint: {'center_x': .5}
        padding: 0, dp(16), 0, 0

        MDLabel:
            text: app.label_text + app.label_text
            halign: 'justify'
            padding: dp(16), dp(16)
            markup: True
            font_style: 'Body1'
            theme_text_color: 'Primary'
            size_hint_y: None
            height: self.texture_size[1]
        MDLabel:
            text: app.label_text + app.label_text
            halign: 'justify'
            padding: dp(16), dp(16)
            markup: True
            font_style: 'Body1'
            theme_text_color: 'Primary'
            size_hint_y: None
            height: self.texture_size[1]
        Widget
""")


class ExampleCenter(FloatLayout):
    pass


class Example(MDApp):
    title = "Dialogs"
    label_text = LIPSUM

    def build(self):
        return ExampleCenter()


Example().run()

我怎样才能编译它们并使其工作?

【问题讨论】:

    标签: python-3.x kivy kivy-language


    【解决方案1】:

    问题是您试图在 ScrollView 的子代中使用 pos_hint(它不尊重该属性)。因此,与其尝试将ScrollView 的子元素居中,不如将ScrollView 本身居中。这意味着ScrollView 必须放在Layout 内。所以,如果你使用FloatLayout,你可以这样做:

    <ExampleFL>:
        ScrollView:
            pos_hint: {'center_x': .5}
            size_hint_x: None
            width: grid.width
    
            do_scroll_x: False
            bar_width: 10
            bar_color: app.theme_cls.primary_color
            bar_color_acrive: app.theme_cls.accent_color
            effect_cls: "DampedScrollEffect"
            scroll_type: ['bars']
    
            GridLayout:  # If FloatLayout and BoxLayout, doesn't scroll!
                id: grid
            .
            .
            .
    

    并创建ExampleFL 类:

    class ExampleFL(FloatLayout):
        pass
    

    这会将ScrollView 的宽度设置为其子GridLayout 的宽度,并使用pos_hintScrollView 置于ExampleFL 内的中心。那么你的build 方法当然会返回ExamplFL()

    【讨论】:

    • 应用您的更改后,size_hint_x: .75size_hint_max_x: dp(800)size_hint_min_x: min(dp(400) , root.width) 在 GridLayout 中不再起作用,它错过了漂亮的布局调整大小。
    • 您再次尝试在不支持此类属性的 ScrollView 的子代中使用 hints。您可以将此类提示应用于ScrollView 本身(因为它们由包含FloatLayout 处理)。您还可以将size_hint 用于GridLayout(但不是pos_hint)的子代,因为它们再次由包含GridLayout 处理。
    • 无法以这种方式达到我想要的结果。我将以编程方式在 ScrollView 中实现居中。
    【解决方案2】:

    在 ScrollView 中以编程方式实现居中视图以控制填充。这给了我想要的结果。

    from kivymd.app import MDApp
    from kivy.lang import Builder
    from kivy.metrics import dp
    from kivy.properties import NumericProperty
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.gridlayout import GridLayout
    
    
    LIPSUM = """Very long lipsum..."""
    
    
    Builder.load_string("""
    <ExampleScroll@FloatLayout>:
        ScrollView:
            do_scroll_x: False
            bar_width: 10
            bar_color: app.theme_cls.primary_color
            bar_color_acrive: app.theme_cls.accent_color
            effect_cls: "DampedScrollEffect"
            scroll_type: ['bars']
    
            ScrollCenterLayout:
                cols: 1
                rel_max: dp(800)
                rel_min: dp(400)
                orientation: 'vertical'
                size_hint_y: None
                height: self.minimum_height
    
                MDLabel:
                    text: app.label_text + app.label_text
                    halign: 'justify'
                    padding: dp(16), dp(16)
                    markup: True
                    font_style: 'Body1'
                    theme_text_color: 'Primary'
                    size_hint_y: None
                    height: self.texture_size[1]
                MDLabel:
                    text: app.label_text + app.label_text
                    halign: 'justify'
                    padding: dp(16), dp(16)
                    markup: True
                    font_style: 'Body1'
                    theme_text_color: 'Primary'
                    size_hint_y: None
                    height: self.texture_size[1]
                Widget
    """)
    
    
    class ScrollCenterLayout(GridLayout):
        rel_max = NumericProperty(dp(800))
        rel_min = NumericProperty(dp(400))
    
        def __init__(self, **kwargs):
            super(ScrollCenterLayout, self).__init__(**kwargs)
    
            self.rel_max = kwargs.get('rel_max', dp(800))
            self.rel_min = kwargs.get('rel_min', dp(400))
    
        def on_width(self, instance, value):
            if self.rel_max < value:
                padding = max(value * .125, (value - self.rel_max) / 2)
            elif self.rel_min < value:
                padding = min(value * .125, (value - self.rel_min) / 2)
            elif self.rel_min < value:
                padding = (value - self.rel_min) / 2
            else:
                padding = 0
    
            self.padding[0] = self.padding[2] = padding
    
    
    class ExampleScroll(FloatLayout):
        pass
    
    
    class Example(MDApp):
        label_text = LIPSUM
    
        def build(self):
            self.theme_cls.primary_palette = "LightGreen"
            self.theme_cls.accent_palette = "Green"
            self.theme_cls.theme_style = "Dark"
            return ExampleScroll()
    
    
    Example().run()
    

    【讨论】:

      【解决方案3】:

      你要做的是首先,创建一个滚动视图,如果可能,你可以使用 RecycleView,这样你就可以轻松地将小部​​件添加为已定义为小部件的类:

      例子:

      class Thing1(AnchorLayout):
          pass
      
      Kv ="""
      <Thing1>:
          anchor_x: "center"
          MDIconButton:
              icon: "hi.png"
      
      
      """
      

      现在,无论您定义了 scrollview 或 recycleview 小部件 ID,请执行以下操作:

      app.root.ids.scrollview_id_of_your_widget.add_widget(Thing1())
      

      或者,如果您使用的是 RecycleView

      app.root.ids.scrollview_id_of_your_widget.data.append({"viewclass": "Thing1", })
      

      滚动视图上的小部件将居中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-12
        • 1970-01-01
        相关资源
        最近更新 更多