Here the columns are in the middle:
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.uix.relativelayout import RelativeLayout
from kivy.metrics import dp
from kivy.utils import get_random_color
from kivy.properties import ColorProperty, ListProperty
kv = """
BoxLayout:
orientation: 'vertical'
spacing: dp(2)
ScrollView:
BoxLayout:
size_hint_y: None
height: self.minimum_height
Widget:
GridLayout:
id: grid
cols:2
spacing: '2dp'
size_hint: None, None
size:self.minimum_size
Widget
Button:
size_hint_y: None
height: dp(48)
text: 'grow'
on_release: app.grow_image()
<MyButton>:
size_hint:None,None
size:'60dp','60dp'
Widget:
id: w
size_hint:None,None
size:'60dp','60dp'
canvas:
Color:
rgba: root.bg_color
Rectangle:
size: root.bg_size
pos: root.bg_pos
"""
class MyButton(RelativeLayout):
bg_color = ColorProperty()
bg_size = ListProperty([dp(60), dp(60)])
bg_pos = ListProperty([0, 0])
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.anim_grow = (Animation(bg_size=(dp(62), dp(62)), bg_pos=(dp(-1), dp(-1)), duration=0.5) +
Animation(bg_size=(dp(60), dp(60)), bg_pos=(0, 0), duration=0.5))
def grow(self):
self.anim_grow.start(self)
class MyApp(App):
def build(self):
return Builder.load_string(kv)
def on_start(self):
for _ in range(22):
self.root.ids.grid.add_widget(MyButton(bg_color=get_random_color()))
def grow_image(self):
for w in self.root.ids.grid.children:
w.grow()
if __name__ == '__main__':
MyApp().run()