kivymd / KivyMD

KivyMD is a collection of Material Design compliant widgets for use with Kivy, a framework for cross-platform, touch-enabled graphical applications. https://youtube.com/c/KivyMD https://twitter.com/KivyMD https://habr.com/ru/users/kivymd https://stackoverflow.com/tags/kivymd
https://kivymd.readthedocs.io
MIT License
2.26k stars 676 forks source link

Tab contents MDBoxLayout adaptive_width mis-layout. #1665

Open RobertFlatt opened 8 months ago

RobertFlatt commented 8 months ago

Description of the Bug

An MDBoxLayout in tabs content is mis-layedout when adaptive_width = True. In this case the intent is for "Button in BoxLayout" to be located centrally in the space below "Button 2"

adaptive_size correctly lays out the BoxLayout if the design intent is for the layout to behave as if there is no BoxLayout.

Code and Logs

from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView

from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDButton, MDButtonText
from kivymd.uix.tab import (
    MDTabsItemIcon,
    MDTabsItemText,
    MDTabsItem,
)

KV = '''
MDScreen:
    md_bg_color: self.theme_cls.backgroundColor
    MDBoxLayout:
        orientation:'vertical'
        MDTabsPrimary:
            id: tabs
            pos_hint: {"center_x": .5, "center_y": .5}
            MDDivider:
            MDTabsCarousel:
                id: related_content_container
                size_hint_y: None
                height: dp(320)
        MDLabel:
            text:'Button BoxLayout has adaptive_width = True.'
            halign:'center'
'''

class Example(MDApp):
    def on_start(self):
        super().on_start()
        self.root.ids.tabs.add_widget(
            MDTabsItem(MDTabsItemText(text='A Tab')))

        bl = MDBoxLayout(orientation='vertical',
                         size_hint_y=None)
        bl.bind(minimum_height=bl.setter('height'))
        for i in range(3):
            bl.add_widget(MDButton(MDButtonText(text='Button '+str(i)),
                                   pos_hint={"center_x": .5, "center_y": .5}))

        bl2 = MDBoxLayout(orientation='horizontal',
                          pos_hint = {'center_x':0.5},
                          adaptive_width = True)
        bl2.add_widget(MDButton(MDButtonText(text='Button in BoxLayout'),
                                pos_hint={"center_x": .5, "center_y": .5}))
        bl.add_widget(bl2)

        sv = ScrollView()
        sv.add_widget(bl)
        self.root.ids.related_content_container.add_widget(sv)

    def build(self):
        self.theme_cls.primary_palette = "Olive"
        return Builder.load_string(KV)

Example().run()

Screenshots

issue5

Versions

RobertFlatt commented 8 months ago

@HeaTTheatR

The problem is the size_hint_y in the box layout at the root of the tab content.

This is a workaround for the example above, but its not a fix (see end of this post)

        bl = MDBoxLayout(orientation='vertical',
                         #size_hint_y=None)
                         )

To be clear it is unrelated to Tab, so a simpler example is:

from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDButton, MDButtonText

class Example2(MDApp):

    def build(self):
        self.theme_cls.primary_palette = "Olive"
        bl = MDBoxLayout(orientation='vertical',
                         pos_hint = {'center_y':0.5},
                         size_hint_y=None)    ####### this is the cause
                         #)
        for i in range(3):
            bl.add_widget(MDButton(MDButtonText(text='Button '+str(i)),
                                   pos_hint={"center_x": .5, "center_y": .5}))

        bl2 = MDBoxLayout(orientation='horizontal',
                          pos_hint = {'center_x':0.5},
                          adaptive_width = True)
        bl2.add_widget(MDButton(MDButtonText(text='Button in BoxLayout'),
                                pos_hint={"center_x": .5, "center_y": .5}))
        bl.add_widget(bl2)

        return bl

Example2().run()

This is I think still a real issue, because the size_hint_y=None is required in the original example for ScrollView so that if for i in range(3): is for i in range(10): the content will scroll correctly. So in the original with more buttons one can have scrolling or adaptive_width but not both.

RobertFlatt commented 8 months ago

FYI typo in https://kivymd.readthedocs.io/en/latest/components/boxlayout/ image

I think last line should be width: self.minimum_width

FYI I re-designed my app to avoid the 'adaptive_width with scroll' issue (and its better!), so my priority on this one is now zero.