Scrollview with multiple custom widgets

351 views
Skip to first unread message

Shoumik Das

unread,
Jul 20, 2020, 7:09:43 AM7/20/20
to Kivy users support
Hi! I am trying to play around withe scroll view a bit but I can't seem to get it working. I have made a custom widget as follows:

Python

class StatusRecord(BoxLayout):
pass

Kivy

<StatusRecord>:
orientation: 'vertical'
size_hint_x: 0.95
size_hint_y: None
pos_hint: {'center_x':0.5}
height: '90dp'
BoxLayout:
orientation: 'horizontal'
canvas.after:
Color:
rgba: 128/255, 128/255, 128/255, 1
Line:
width: dp(1)
rectangle: (*self.pos, self.width, self.height)
Label:
canvas.after:
Color:
rgba: 128/255, 128/255, 128/255, 1
Line:
width: dp(1)
rectangle: (*self.pos, self.width, self.height)
size_hint_x: 0.8
markup: True
color: 0, 0, 0, 1
text: 'Date'
ImageButton:
size_hint_x: 0.2
source: {'normal': 'images/edit-48.png', 'down': 'images/edit-green-48.png'} [self.state]
BoxLayout:
orientation: 'horizontal'
canvas.after:
Color:
rgba: 128/255, 128/255, 128/255, 1
Line:
width: dp(1)
rectangle: (*self.pos, self.width, self.height)
Label:
canvas.after:
Color:
rgba: 128/255, 128/255, 128/255, 1
Line:
width: dp(1)
rectangle: (*self.pos, self.width, self.height)
size_hint_x: 0.8
markup: True
color: 0, 0, 0, 1
text: 'Message'
ImageButton:
size_hint_x: 0.2
source: {'normal': 'images/trash-48.png', 'down': 'images/trash-green-48.png'} [self.state]
Label:

This is how I implemented ScrollView: essentially put a box layout inside the scroll view since it can accept only 1 widget. Then added multiple custom widgets inside the box layout for getting the scroll effect.

Kivy

<SivaStatusScreen>:
dropdown: dropdown.__self__
name: 'status_screen'
canvas.before:
Color:
rgba: 255/255, 255/255, 255/255, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
id: status_layout
orientation: 'vertical'
BoxLayout:
id: actionbar_layout
size_hint_y: None # size the box layout to contain the action bar
height: 48 # width of the action bar in line with the minimum dimensions of the icons
ActionBar:
id: status_actionbar
pos_hint: {'top': 1}
background_image: ''
background_color: 195/255, 60/255, 35/255, 1
ActionView:
use_separator: True
ActionPrevious:
title: 'SIVA'
with_previous: False
ActionOverflow:
CustomActionButton:
id: status-button
important: True
source: {'normal': 'images/communicationgreen-48.png', 'down': 'images/communication-48.png'} [self.state]
on_release: root.to_statusscreen()
CustomActionButton:
id: accounts-button
important: True
source: {'normal': 'images/key-48.png', 'down': 'images/keygreen-48.png'} [self.state]
on_release: root.to_accountsscreen()
CustomActionButton:
id: bot-button
important: True
source: {'normal': 'images/bot-48.png', 'down': 'images/botgreen-48.png'} [self.state]
on_release: root.to_botscreen()
CustomActionButton:
id: logout-button
important: True
source: {'normal': 'images/shutdown-48.png', 'down': 'images/shutdowngreen-48.png'} [self.state]
on_release: root.to_logout()
BoxLayout:
id: status_display
# size_hint is not needed. This Layout shares space with the BoxLayout that has a fixed y size, it will grow to fill the space.
orientation: 'vertical'
BoxLayout:
id: status_label
size_hint_y: None
height: 40
orientation: 'horizontal'
BoxLayout:
orientation: 'horizontal'
Image:
keep_ratio: True
source: 'images/communication-48.png'
Label:
text: 'Status'
markup: True
color: 0, 0, 0, 1
ImageLabelButtonTop:
# conflict in the on_release defined for ImageLabelButton and this instance.
id: parent_button
source: 'images/expand-arrow-48.png'
text: 'User'
on_release:
# root.add_dd_values()
dropdown.open(self)
on_parent: dropdown.dismiss()
size_hint_y: None
height: '40dp'
DropDown:
id: dropdown
on_select:
# args is a reserved keyword which returns only two values: object alias (0) and data (1).
parent_button.text = args[1][0]
parent_button.source = args[1][1]
# Invoked inside dropdown
# root - Screen, self - DropDown object
ImageLabelButton:
source: 'images/twitter-circled-48.png'
text: 'Twitter'
ImageLabelButton:
source: 'images/linkedin-circled-48.png'
text: 'LinkedIn'
ScrollView:
do_scroll_x: False
do_scroll_y: True
BoxLayout:
id: status_content
orientation: 'vertical'
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
AnchorLayout:
id: status_add
anchor_x: 'right'
anchor_y: 'bottom'
ImageButton:
id: status_addbtn
source: {'normal': 'images/plus-96.png', 'down': 'images/plusblue-96.png'} [self.state]
size_hint: 0.2, 0.2
on_release: root.new_status_entry()

But the custom widgets do not scroll. Only 3 out of 7 custom widgets are visible. Here is the screenshot. Can you please advise as to what I am doing wrong? Additionally, the widget under the plus button (bottom-right corner) is not clickable due to overlap. Is there a way to restrict the ScrollView view-port to just above the plus button?



Thanks in advance.

Elliot Garbus

unread,
Jul 20, 2020, 11:56:02 AM7/20/20
to Kivy users support
You need to set the size of the BoxLayout under the Scrollview.

Shoumik Das

unread,
Jul 21, 2020, 5:31:44 AM7/21/20
to Kivy users support
Hi Elliot,

I tried several size_hint combinations with the Box Layout but was unable to make it work. So, I did some look up on Google and tried with a Grid Layout (cols: 1). Now the widgets are scrolling but I can't seem to center them horizontally. The pos_hint is not working. Can you suggest how I may achieve the centering?

Also, how can I restrict the widgets to not cross the plus button on the bottom-right corner?

Following is my modified Kivy code:

GridLayout:
id: status_content
cols: 1
height: self.minimum_height
pos_hint: {'center_x':0.5}
size_hint_x: 0.9
size_hint_y: None
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
AnchorLayout:
id: status_add
anchor_x: 'right'
anchor_y: 'bottom'
ImageButton:
id: status_addbtn
source: {'normal': 'images/plus-96.png', 'down': 'images/plusblue-96.png'} [self.state]
size_hint: 0.2, 0.2
on_release: root.new_status_entry()


Your suggestions are highly appreciated. Thanks.

Elliot Garbus

unread,
Jul 21, 2020, 10:56:49 AM7/21/20
to kivy-...@googlegroups.com

I’m not certain this address all your concerns but it is a simpler exaample to play with.

A few things to highlight.  I used Labels without text in a BoxLayout to position other objects in the Layout.

 

I created a BoxLayout below the ScrollView and put a proxy for the green +, using a button.

 

 

from kivy.app import App
from kivy.lang import Builder


kv =
'''
<InfoLine@BoxLayout>:
    size_hint_y: None
    height: 48
    Label:
        size_hint_x: .25
    Button:
        text: 'Left'
    Button:
        text: 'Right'
    Label:
        size_hint_x: .25


BoxLayout:
    orientation: 'vertical'
    BoxLayout:  # Line 1
        size_hint_y: 1
        Label:
            text: 'Scroll View Test'
    ScrollView:
        size_hint_y:8
        do_scroll_x: False
        do_scroll_y: True
        scroll_type: ['bars', 'content']
        bar_width: 20
        BoxLayout:
            orientation: 'vertical'
            size_hint_y: None
            height: self.minimum_height
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
            InfoLine:
    BoxLayout:
        size_hint_y: None
        height: 48 
        Label: # Placeholder        
        Button:                 # This could go in a vertical of horizontal layout to be outside the scrollview
            size_hint_x: None
            width: 48
            text: '+'
       
'''


class ScrollTestApp(App):

   
def build(self):
       
return Builder.load_string(kv)


ScrollTestApp().run()

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/76062dd7-331b-40ab-875d-ff4f77b8b378o%40googlegroups.com.

 

Shoumik Das

unread,
Jul 22, 2020, 12:29:38 PM7/22/20
to Kivy users support
Elliot - I used your code as reference to tweak my code and the widgets are now centering but I am still having some issues with the overlap of the plus button (bottom-right) in the anchor layout. Can you please help me understand the significance of the size_hints mentioned below in your code in yellow. I am unable to understand the purpose. I have a fixed height action bar at the top followed by another fixed-height label row just below. I was expecting the boxlayout/scroll view defined under it to automatically occupy the remaining portion of the screen.

Your code

BoxLayout:
    orientation: 'vertical'
    BoxLayout:  # Line 1
        size_hint_y: 1 # 1 refers to the full height of the y-axis. But the label only occupies a small portion at the top. Why is this needed?
        Label:
            text: 'Scroll View Test'
    ScrollView:
        size_hint_y:8 # I thought size_hint_y would have to be in a range of 0 to 1. What does 8 signify?

I tweaked my code as follows:

scroll_type: ['bars', 'content']
bar_width: 20
BoxLayout:
id: status_content
orientation: 'vertical'
height: self.minimum_height
size_hint_y: None
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
BoxLayout:
size_hint_y: None
height: 48
Label:
id: scrollview_buttonspacer
AnchorLayout:
id: status_add
anchor_x: 'right'
anchor_y: 'bottom'
ImageButton:
id: status_addbtn
source: {'normal': 'images/plus-96.png', 'down': 'images/plusblue-96.png'} [self.state]
size_hint: 0.2, 0.2
on_release: root.new_status_entry()


My plus button is still over-lapping the widgets. Should I remove the anchor layout and convert it into a button inside a box layout as you have done in your code?

Please advise. Sorry for bothering you but I am new to Kivy and still learning the fine points of this framework.

Thanks in advance.



To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Elliot Garbus

unread,
Jul 22, 2020, 4:38:27 PM7/22/20
to kivy-...@googlegroups.com

You can think about the hints as being relative.  They are one by default.  I think about them like this.  The hints in a layout are relative to the sum of the hints.

 

If I have 3 equal size objects in a boxlayout, all with the hint 1, each ends up 1/3 of the screen.  The same is true as long as the hints are the same value.  For example same 3 widgets in a boxlayout, If I set the size hint in each of the to 10, they will still end up 1/3 of the screen.

 

So having 1 and 8 is the same as having .1 and .8.  

 

I have a fixed height action bar at the top followed by another fixed-height label row just below. I was expecting the boxlayout/scroll view defined under it to automatically occupy the remaining portion of the screen.

 

I updated my example to have a fixed size Label on the top and bottom.

 

from kivy.app import App
from kivy.lang import Builder


kv =
'''

<InfoLine@BoxLayout>:
    size_hint_y: None
    height: 48
    Label:
        size_hint_x: .25
    Button:
        text: 'Left'
    Button:
        text: 'Right'
    Label:
        size_hint_x: .25


BoxLayout:
    orientation: 'vertical'
    BoxLayout:  # Line 1
        size_hint_y: None
        height: 48

        Label:
            text: 'Scroll View Test'
    ScrollView:

Your suggestions are highly appreciated. Thanks.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/dfe4a9b9-20b2-456f-ade8-e65c23dc4d5co%40googlegroups.com.

 

Elliot Garbus

unread,
Jul 22, 2020, 4:45:39 PM7/22/20
to kivy-...@googlegroups.com

Re: size_hints pulling a line from the docs: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=size_hint#kivy.uix.widget.Widget.size_hint_x

When multiple widgets can share a row of a layout, such as in a horizontal BoxLayout, their widths will be their size_hint_x as a fraction of the sum of widget size_hints.

 

 

From: Elliot Garbus
Sent: Wednesday, July 22, 2020 1:38 PM
To: kivy-...@googlegroups.com
Subject: RE: [kivy-users] Re: Scrollview with multiple custom widgets

 

You can think about the hints as being relative.  They are one by default.  I think about them like this.  The hints in a layout are relative to the sum of the hints.

 

If I have 3 equal size objects in a boxlayout, all with the hint 1, each ends up 1/3 of the screen.  The same is true as long as the hints are the same value.  For example same 3 widgets in a boxlayout, If I set the size hint in each of the to 10, they will still end up 1/3 of the screen.

 

So having 1 and 8 is the same as having .1 and .8.  

 

I have a fixed height action bar at the top followed by another fixed-height label row just below. I was expecting the boxlayout/scroll view defined under it to automatically occupy the remaining portion of the screen.

 

I updated my example to have a fixed size Label on the top and bottom.

 

from kivy.app import App
from kivy.lang import Builder


kv =
'''

<InfoLine@BoxLayout>:
    size_hint_y: None
    height: 48
    Label:
        size_hint_x: .25
    Button:
        text: 'Left'
    Button:
        text: 'Right'
    Label:
        size_hint_x: .25


BoxLayout:
    orientation: 'vertical'
    BoxLayout:  # Line 1
        size_hint_y: None
        height: 48

        Label:
            text: 'Scroll View Test'
    ScrollView:

Shoumik Das

unread,
Jul 23, 2020, 11:39:06 AM7/23/20
to Kivy users support
Thank you very much for helping me understand. My app is now working as expected.

This is my final tweaked layout:

ScrollView:
do_scroll_x: False
do_scroll_y: True
scroll_type: ['bars', 'content']
bar_width: 15
BoxLayout:
id: status_content
orientation: 'vertical'
height: self.minimum_height
size_hint_y: None
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
StatusRecord:
BoxLayout:
id: status_add_layout
orientation: 'horizontal'
size_hint_y: None
height: '48dp'
Label:
ImageButton:
id: status_addbtn
size_hint_x: 0.05
size_hint_min_x: 48
source: {'normal': 'images/plus-96.png', 'down': 'images/plusblue-96.png'} [self.state]
on_release: root.new_status_entry()

Screenshot

Elliot Garbus

unread,
Jul 23, 2020, 11:45:01 AM7/23/20
to kivy-...@googlegroups.com

Congratulations! 😊

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/21bd5745-5d91-4e19-ad6f-1e4fb5dcbb44o%40googlegroups.com.

 

Reply all
Reply to author
Forward
0 new messages