I'm trying to make a horizontal scroll view in Kivy (Python) which would display an image (buttons for now) that you can scroll through. I've been able to figure out how to do the horizontal scroll view, but I just can't seem to figure out what I'm doing wrong to center on the screen. Here is what I have so far:
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.rows = 1
self.spacing=50
self.size_hint=(None, .5)
self.bind(minimum_width=self.setter('width'))
class ScrollViewApp(App):
def build(self):
scroll = ScrollView( size_hint=(1,1), do_scroll_x=True, do_scroll_y=False )
grid = MyGrid()
for i in range(60):
grid.add_widget(Button(text='#00' + str(i),size=(100,100), size_hint=(1,1)))
scroll.add_widget(grid)
return scroll
if __name__ == '__main__':
ScrollViewApp().run()
I looked through the documentation and I think it has something to do with pos_hint: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=pos_hint#kivy.uix.widget.Widget.pos_hint
I tried adding:
self.pos={'center_y':1}
in my MyGrid() class, but nothing is being changed. No matter what value is I put after center_y, my the ScrollView contained in the grid still appears at the top of the screen, rather than centered halfway down. I've also tried adjusting things in the ScrollViewApp() class too, using
scroll.pos={'center_y':1}
as well. I can't seem to figure out what I'm doing wrong. Does anyone have any ideas on what I'm not understanding here? I feel like I'm so close!!!
Edit:
I'm trying to have the buttons centered, but also be able to scroll by dragging the black space around the buttons. In the picture below, you can see there is a bunch of black space beneath the buttons. I can click a button or this black space and scroll horizontally. I just need this to happen with the buttons centered!
The layout is behaving as you told it to.
You have a ScrollView
as a root widget, and inside it you put your Grid
that has size_hint_y = 0.5
.
It takes half of the parent widget height, that takes the full window height.
One way to center your Grid
is to put some spacers over and under it, but this is not possible, since ScrollView
accepts onle one widget as content.
So, one solution is to..
Grid
have the full height of the ScrollView
ScrollView
inside another Layout (e.g. a BoxLayout
)ScrollView
in the center.class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.rows = 1
self.spacing = 50
self.size_hint = (None, 1)
self.bind(minimum_width=self.setter('width'))
class ScrollViewApp(App):
def build(self):
base = BoxLayout(orientation="vertical", size_hint=(1, 1))
base.add_widget(Widget(size_hint_y=.3))
scroll = ScrollView(size_hint=(1, .4), do_scroll_x=True, do_scroll_y=False)
grid = MyGrid()
for i in range(60):
grid.add_widget(
Button(text='#00' + str(i), size=(100, 100), size_hint=(1, 1)))
scroll.add_widget(grid)
base.add_widget(scroll)
base.add_widget(Widget(size_hint_y=.3))
return base
if __name__ == '__main__':
ScrollViewApp().run()
Another approach would be to..
ScrollView
inside a FloatLayout
pos_hint
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.rows = 1
# self.spacing = 50
self.size_hint = (None, 1)
self.bind(minimum_width=self.setter('width'))
class ScrollViewApp(App):
def build(self):
base = FloatLayout(size_hint=(1, 1))
scroll = ScrollView(size_hint=(1, .4), do_scroll_x=True, do_scroll_y=False,
pos_hint={"center_y": .5})
grid = MyGrid()
for i in range(60):
grid.add_widget(
Button(text='#00' + str(i), width=100, size_hint=(None, 1)))
scroll.add_widget(grid)
base.add_widget(scroll)
return base
if __name__ == '__main__':
ScrollViewApp().run()
Edit:
OK. After the update of the question, this is a way to to center and use the black bars to scroll:
Builder.load_string("""
<BaseWidget>:
ScrollView:
do_scroll_y: False
BoxLayout:
orientation: "vertical"
size_hint_x: None
width: self.minimum_width
Widget:
size_hint_y: .3
GridLayout:
id: grid
rows: 1
size_hint_y: .4
size_hint_x: None
width: self.minimum_width
Widget:
size_hint_y: .3
""")
class BaseWidget(FloatLayout):
pass
class ScrollViewApp(App):
def build(self):
base = BaseWidget()
for i in range(60):
base.ids.grid.add_widget(Button(text='#00' + str(i),
width=100, size_hint_x=None))
return base
if __name__ == '__main__':
ScrollViewApp().run()
It uses kv_lng
to create the layout because I find it easier to the eye.
For a "Python only" code you can use this:
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.rows = 1
self.size_hint = None, .4
self.bind(minimum_width=self.setter('width'))
class MyBox(BoxLayout):
def __init__(self, **kwargs):
super(MyBox, self).__init__(**kwargs)
self.orientation = "vertical"
self.size_hint_x = None
self.bind(minimum_width=self.setter('width'))
class ScrollViewApp(App):
def build(self):
base = FloatLayout()
grid = MyGrid()
box = MyBox()
box.add_widget(Widget(size_hint_y=.3))
box.add_widget(grid)
box.add_widget(Widget(size_hint_y=.3))
for i in range(60):
grid.add_widget(Button(text='#00' + str(i), width=100, size_hint_x=None))
scroll = ScrollView(do_scroll_y=False, pos_hint={"center_y": .5})
scroll.add_widget(box)
base.add_widget(scroll)
return base
if __name__ == '__main__':
ScrollViewApp().run()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With