Search code examples
pythonandroidkivykivymd

Making a layout that automaitcally has the correct spacing


How do I create a layout object (BoxLayout, GridLayout etc...) where If I pass it x objects and the layout object has a height of y then it automatically assigns a space between objects so that they are all evenly spaced out.

I tried to follow Kivy Layout height to adapt to child widgets's height but I wasn't able to get it to work.

Though I should be able to calculate the space myself I a) couldn't even get this to work and b) I want a layout that will be relatively flexible.

Each button I have is as follows:

class BoxButton(MDCard):
    """Button to click on that can take other objects"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.size_hint = (None, None)
        self.size = ("200dp", "100dp")
        self.pos_hint = {"center_x": 0.5}
        self.size_hint_y = None

And the layout box is being given the full size of the screen.

How can I get a layout that just auto-adjusts the spacing between objects? Thanks


Solution

  • This works. You pass in the objects you want to display and then it adds in an object that does the spacing for you. Seems like a workaround but it does work.

    from kivymd.app import MDApp
    from kivymd.uix.boxlayout import MDBoxLayout
    from kivymd.uix.card import MDCard
    
    from kivy.metrics import dp
    
    
    class GapLayout(MDBoxLayout):
        def __init__(self, widgets, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.orientation = "vertical"
            gap_height = 0
    
            widgets_height = 0
            for widget in widgets:
                widgets_height += widget.height
    
            def update_gap_height(instance, value):
                nonlocal gap_height
                available_height = self.height - widgets_height
                gap_height = (
                    available_height / (len(widgets)+1)
                )  # Divide by the number of gaps
                update_layout()
    
            def update_layout():
                self.clear_widgets()
                for widget in widgets:
                    self.add_widget(widget)
    
                    # Add the gap between cards
                    gap = MDBoxLayout(size_hint=(1, None), height=gap_height)
                    self.add_widget(gap)
    
            self.bind(size=update_gap_height)
    
            update_gap_height(self, self.size)
    

    So for example:

    class TestApp(MDApp):
        def build(self):
            card1 = MDCard(size_hint=(1, None), height=dp(10), md_bg_color=[0, 0, 0, 1])
            card2 = MDCard(size_hint=(1, None), height=dp(10), md_bg_color=[0, 0, 0, 1])
            card3 = MDCard(size_hint=(1, None), height=dp(10), md_bg_color=[0, 0, 0, 1])
            card4 = MDCard(size_hint=(1, None), height=dp(10), md_bg_color=[0, 0, 0, 1])
    
            root = GapLayout([card1, card2, card3, card4])
            return root