Works for me as long as you don't specify any sizing for the ScrollView
.
Change this:
scrollview = ScrollView(size_hint=(None, None), size=(400, 400), pos_hint={'center_x': .5, 'center_y': .5})
...to this:
scrollview = ScrollView()
To keep the buttons square, we can use GridLayout
's row_default_height
:
layout = GridLayout(cols=3, spacing=10, size_hint_y=None, row_force_default=True)
layout.bind(width=lambda *_: setattr(layout, 'row_default_height',
(layout.width - (layout.spacing[0] * (layout.cols - 1))) / layout.cols))
layout.bind(minimum_height=layout.setter('height'))