Search code examples
pythonkivyscrollviewstacklayout

kivy: Problem with the StackLayout's minimum height


I'm trying to do a scrollable list of buttons. When I build the Stack of buttons, the StackLayout has a parameter called minimum_height which is set automatically by the layout (so it says the kivy doc).

But when I run the debug, I find that that parameter is always 0.

I think that it should be changing as I add more buttons, but it does not. And I can´t figure out why.

from kivy.uix.button import Button
from kivy.app import App
from kivy.uix.scrollview import ScrollView
from kivy.uix.stacklayout import StackLayout

class MenuFases(StackLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.btns = []
        for i in range(0, 20):
            self.btns.append(Button(text=f'{i+1}º fase', size_hint=(1, .1)))
            self.add_widget(self.btns[i])
        self.size_hint=(1, None)
        self.height = self.minimum_height
        print(self.minimum_height)

class ScrollMenu(ScrollView):
    def __init__(self, **kwargs):
        super(ScrollMenu, self).__init__(**kwargs)
        fase = MenuFases()
        self.add_widget(fase)

class MyApp(App):
    def build(self):
        return ScrollMenu()

MyApp().run()

Solution

  • Whenever a layout is offering properties like minimum_height, minimum_width, that means it will automatically compute the minimum height (or width) required to contain all its children.

    So here you want it to grow automatically in the vertical direction. But the problems in your code are,

    1. You have not specified the child (here Button) widget's height explicitly, instead you set size_hint_y to 0.1 which means it will be always contained within the layout's space. But again,

    2. You used ScrollView in order to scroll (vertically) whenever the child widgets exceeds layout's bound.

    To solve these 2 problems you have to explicitly specify the child widget's height and make the layout listen to that change (so that whenever the children exceed its boundary you will be able to scroll). For the latter part you have to bind a callback function which will do rest of the job for you. In pure python you have to define it manually but in kv-lang it will take care of it automatically.

    So the changes you need (as I found),

    for i in range(0, 20):
                self.btns.append(
                    Button(
                        text=f'{i+1}º fase',
                        size_hint_y=None, # You need to set...(next line)
                        height = 200, # an explicit value.
                    )
                )
                self.add_widget(self.btns[i])
            self.size_hint=(1, None)
            self.bind(minimum_height = self.setter("height")) # Listen to the change and set height accordingly.