I am trying to understand how StackLayout works within ScrollView in Kivy. And i have got a problem. I do not know how to insert a widget to the beginning of the layout. If i use .add_widget() method, it adds the widget to the end(in the bottom) of the layout. And if i change the orientation of the layout(it
has stacking id) to 'lr-bt' and then add the widget(with "Title" and "Print" labels), then it causes some padding from the top of the ScrollView. So here is what i get:
May we could use other layouts. If anyone could help me fix that top padding or insert widget to the beginning, that would be great. Thanks.
Here is some code from .py file:
pln = Plan(text_label="Title", text="Print")
self.root.ids.stacking.add_widget(pln)
And here is my ScrollView with the StackLayout from .kv file:
BoxLayout:
id: stack_box
size_hint_y: 1
pos: 2, root.height-1057
RecycleView:
scroll_y: 1
do_scroll_x: False
do_scroll_y: True
size_hint: 1, None
height: 1000
id: scroll_plans
StackLayout:
spacing: 10
padding: 10
id: stacking
orientation: 'lr-bt'
size_hint_y: None
height: 9000
Related
So I am making an app that requires me to load a list of custom widgets(MDCards) into a RecycleView. Each MDcard will contain two labels and a checkbox. The text can be any size and thus the MDCard has to change its height based on the text that it contains. Here is the part in the kv file that deals with this...NOTE: the text i am adding now is temporary to allow me to create different cards with progressively larger heights.
Custom MDCARD Widget
<IndivualReminderElementBlueprint#MDCard>:
md_bg_color:218/255,68/255,83/255,1
size_hint: 1, None
text: ''
Label:
on_size: root.height = self.height
size_hint: 1, None
text_size: root.width, None
size: self.texture_size
text: root.text
The kv code for the RecycleView class
<ListViewBlueprint>:
viewclass: 'IndivualReminderElementBlueprint'
data: [{"text": f"{i} {'test'*i**2}"} for i in range(20)]
RecycleBoxLayout:
id: container
default_size: None, None
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing:'20dp'
I am aware that this jerkiness in the scrolling is caused because the size of the widgets is calculated as the user scrolls down which also causes the scroll position to jump randomly. I also looked into this issue posted on Github https://github.com/kivy/kivy/issues/6582 . But i am unable to understand the code at the end or if it will actually fix this problem? I was also wondering if there was any other way to fix this problem? Thanks :)
class Template_Screen (Screen):
pass
Above is the class which i have added into a App class as follows
class MAKE_HTML(App):
"""
Still i need to write it fully.... Thanks for patience.....
"""
def build(self):
sm = ScreenManager()
sm.add_widget(Template_Screen(name='Select Template'))
I am using the kv file which is as follows
#the below screen gives the template
<Template_Screen>
ScrollView:
do_scroll_y:True
do_scroll_x: False
GridLayout:
size_hint_y:None
cols:1
height:self.minimum_height
BoxLayout:
Image:
source: "Images/Templates Pictures/Temp-1.png"
Label:
text:"Some sort of text\n Some text"
Problems:
When I scroll, the scroll first scrolls and then goes up even if i do not scroll up. i.e, After scrolling down-> Automatically goes up.
The image is not visible. I want the image to be 1/2 the size of screen.
I want to scroll with above like o/p.
The default value for effect_cls of a ScrollView is DampedScrollEffect, which the documentation describes as:
DampedScrollEffect: The current default. Allows the user to scroll
beyond the normal boundaries, but has the content spring back once the
touch/click is released.
So that is the automatic scrolling effect that you see. You can eliminate that behavior by using ScrollEffect as the effect_cls, but that will also prevent you from scrolling when the contents do not fill the ScrollView
When you use height:self.minimum_height for a GridLayout, you must provide a height for each child. Since you want the Image to be half the size of the Screen, you can use a kv like this:
#the below screen gives the template
<Template_Screen>
ScrollView:
do_scroll_y:True
do_scroll_x: False
effect_cls: 'ScrollEffect'
GridLayout:
size_hint_y:None
cols:1
height:self.minimum_height
BoxLayout:
size_hint: None, None
size: root.width/2, root.height/2
Image:
source: "mages/Templates Pictures/Temp-1.png"
allow_stretch: True
keep_ratio: True
Label:
text:"Some sort of text\\n Some text"
size_hint: None, None
size: self.texture_size
Ok, so I'm building something with Kivy(1.11.1) and summarizing I have a ScrollView that scrolls vertically and inside it there are some others ScrollViews but these ones only scroll horizontally, the problem is that whenever I scroll the outer ScrollView down and the mouse position gets into the inner Horizontal ScrollViews the outer Scrollview stops scrolling down, it looks like once the mouse position collides with the horizontal scrollview the scroll behavior stops being sent to the outer ScrollView (vertical) so it stops scrolling down. What I want is something like the Netflix page, in which there are some scrollviews horizontally (My List, Series, Horror Movies, etc) that you can scroll to see more options but they're all inside an outer scrollview that scrolls vertically, of course that in Netflix when you scrolldown even if your mouse position get inside one of the horizontal scrollviews it still continue scrolling the outer ScrollView down.
I've tried setting the horizontall scrollview do_scroll_y to False but the problem goes on. Besides that. Scrolling up works just fine
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
Builder.load_string(
'''
<ScrollApp>:
ScrollView:
bar_width: 10
scroll_type: ['bars', 'content']
BoxLayout:
id: content
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
padding: 22, 0, 22, 50
spacing: 50
canvas:
Color:
rgba: .15, .15, .15, .9
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint: None, None
width: 100
height: 100
on_press: print('pressed')
# "ScrollViews containers"
Custom
Custom
Custom
Custom
<Custom#BoxLayout>:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
Label:
size_hint: None, None
size: self.texture_size
id: label
font_size: 20
ScrollView:
size_hint: 1, None
height: 150
do_scroll: True, False
on_scroll_start: print('scrolling. but why?')
GridLayout:
id: grid
size_hint: None, None
size: self.minimum_width, 150
spacing: 5
cols: 3
Button:
size_hint: None, None
size: 400, 150
Button:
size_hint: None, None
size: 400, 150
Button:
size_hint: None, None
size: 400, 150
''' )
class ScrollApp(BoxLayout):
pass
class Test(App):
def build(self):
return ScrollApp()
Test().run()
I can't claim to understand this situation completely, but it seems that vertical ScrollView inside another vertical ScrollView works. So, a work around is to make the ScrollView inside your Custom class to allow vertical scrolling (along with the horizontal scrolling). To do this, change the kv for the ScrollView inside Custom to:
ScrollView:
size_hint: 1, None
height: 150
do_scroll: True, True # allow vertical scrolling also
on_scroll_start: print('scrolling. but why?')
GridLayout:
id: grid
size_hint: None, 1.01 # height must be slightly greater than ScrollView height
width: self.minimum_width
In order for the vertical scrolling to work in the above, the height of the GridLayout must be larger than the height of the ScrollView, thus the 1.01 size hint.
I will say first off I have tried every single example on the web involving kv lang. Not once have I had any success.
The idea is pretty simple: As I swipe up/down/scroll the contents of GridLayout() within ScrollView() are scrolled up or down.
The best I have been able to do is have the scroll bar fade into view when running the program. Not able to scroll unfortunately.
<Root>
grid_layout: grid_layout
ScreenManager:
...
Screen:
...
ScrollView:
GridLayout:
id: grid_layout
size_hint_y: None
cols: 1
height: self.minimum_height
<list of buttons>
Binding minimum_heightin the __init__ method of the root class (RelativeLayout):
grid_layout = ObjectProperty(None)
self.grid_layout.bind(minimum_height=self.grid_layout.setter('height'))
I have followed https://github.com/kivy/kivy/blob/master/examples/widgets/scrollview.py converting it to kv lang - scroll bar visible, unable to scroll. Also tried every example on Google Groups and here related to using kv lang. Still no scroll :\
Compiling using buildozer and running on Android fails for an unknown reason.
I would appreciate any assistance that can be given.. I am completely clueless at this point
This:
height: self.minimum_height
should be:
minimum_height: self.height
This is unnecessary:
grid_layout = ObjectProperty(None)
self.grid_layout.bind(minimum_height=self.grid_layout.setter('height'))
It also won't scroll unless the contents are larger than the scrollview's height:
Full code:
from kivy.lang.builder import Builder
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<Root>:
ScrollView:
size_hint: 1, .1
# setting the width of the scrollbar to 50pixels
bar_width: 50
# setting the color of the active bar using rgba
bar_color: 5, 10, 15, .8
# setting the color of the inactive bar using rgba
bar_inactive_color: 5, 20, 10, .5
# setting the content only to scroll via bar, not content
scroll_type: ['bars']
GridLayout:
size_hint_y: None
cols: 1
minimum_height: self.height
Button
text: 'one'
Button:
text: 'two'
Button:
text: 'three'
Button:
text: 'four'
''')
class Root(FloatLayout):
pass
class DemoApp(App):
def build(self):
return Root()
if __name__ == '__main__':
DemoApp().run()
Being unable to scroll was due to a misunderstanding of Kivy's touch handlers. Completely unrelated to the code mentioned in my question.
The key is to have GridLayout be larger than ScrollView, so GridLayout can be panned within ScrollView.
For those wanting to use ScrollView inside ScreenManager using kvlang only:
ScreenManager:
id: screen_manager
Screen:
manager: screen_manager
id: main_screen
name: 'main'
ScrollView:
bar_width: 4
# pos_hint defaults to 1,1 so no need to declare it
GridLayout:
size_hint_y: None
cols: 1
# you do not need to manually bind to setter('height') in
# python - perfectly possible with kv lang
# this allows for height to update depending on the
# collective heights of its child widgets
height: self.minimum_height
<----- widgets here ----->
# for scroll to show/work there must be more widgets
# then can fit root.height. If not there is no need
# for scrollview :)
Have a look at the screenshot below:
I kinda new in this Kivy layout scheme, previously I work a lot in PyQt. In PyQt, that blank vertical space can easily get rid of by using Spacer. But how do you do this in Kivy? Below is part of the KV file that constitute this layout.
GridLayout:
cols: 1
GridLayout:
cols: 2
row_default_height: '48dp'
row_force_default: True
spacing: 10, 10
padding: 10, 10
Label:
size_hint: None, None
text: 'Input'
halign: 'left'
valign: 'top'
text_size: self.size
width: 50
TextInput:
id: txt_url
size_hint: 1, None
text: ''
TabbedPanel:
id: tp
do_default_tab: False
TabbedPanelItem:
id: tab_fl
text: ''
TabbedPanelItem:
text: ''
FloatLayout
id: box
TabbedPanelItem:
text: ''
FloatLayout
id: box
I Would love to know what is the best practice of using Kivy layout mechanism. :)
In this case, you can take advantage of the GridLayout's minimum_height property to size it appropriately.
GridLayout:
cols: 1
GridLayout:
cols: 2
row_default_height: '48dp'
row_force_default: True
spacing: 10, 10
padding: 10, 10
# add these two lines
size_hint_y: None
height: self.minimum_height
...
Because you're using one column width in your root GridLayout, it be possible to resize the rows based off children height using the following trick for setting rows_minimum.
GridLayout:
cols: 1
row_force_default: True
## Call it what ya like, just interested in setting 'self.rows_minimum'
foo: [self.rows_minimum.update({i: x.height}) for i, x in enumerate(reversed(list(self.children)))]
## ... rest of layout ...
The internal GridLayout and TabbedPanel are the rows/children of your root GridLayout, so setting heights for the internal elements should allow for the foo generator redirection to pull-up the excess space.
Now for readers that may have more than one column there be a more extensive example, that shows one way of handling auto-sizing of grid layouts and a bunch of other goodies, over at another answer regarding text input word wrapping.