Reputation: 137
Im writing a news app in Kivy that takes articles from a front page of a website and makes them viewable in the app. Depending on the articles length the size and number of paragraphs may vary. Since it uses a BS4 webscraper to exctract the contents of a website, the whole gui programming takes place in python, not in .kv language. So, my question is, how can I stop the Image
from reserving space on screen (I want the labels to always be under it) and how can I change the height
of a BoxLayout
based on its children so there is enough space for all of them, but not too much.
Here is a simplified version of my code that demonstrates my problem. In this example the height of a BoxLayout
is set to 1000dp
which is fine for roughly 4 paragraphs but if there were to be more it would become to cluttered. Is there a way to avoid this problem? Any help will be useful.
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from kivy.uix.screenmanager import Screen
from kivy.uix.scrollview import ScrollView
from kivy.uix.image import AsyncImage
class RootWidget(Screen):
def __init__(self, **kw):
super().__init__(**kw)
self.update()
def update(self):
paragraphs_text = ["Lorem ipsum dolor sit amet,", "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut"
" labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
"laboris nisi ut aliquip ex ea commodo consequat.", "Duis aute irure dolor in reprehenderit in"
" voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."]
header_text = "Lorem ipsum dolor sit amet"
header_image_src = "images/Cariboo_Peaks.jpg"
date_of_publishing_text = "03.05.2020"
scroll_widget_holder = ScrollView()
widget_holder = BoxLayout(orientation="vertical", size_hint_y=None, padding=5)
# minimum_height doesnt work in python, only in .kv language so is there a way to get the height automatically?
# 1000dp works fine for this amount of paragrpahs but i there was twice as many as there are now it would all
# become to cludderd and the image would be very small
# on the other hand, if I make this number too big the wigets are too far apart from each other
# So how can I fix this?
widget_holder.height = "1000dp"
header_image = AsyncImage(source=header_image_src, size_hint=(1, 1),
allow_stretch=False, keep_ratio=True)
header_label = MDLabel(text=header_text, size_hint_y=None, font_style="H6")
# Thats what I came up with, if there is a better way of automatically asigning the height of a widget based
# on its contents please let me know
header_label.height = str(len(header_label.text)) + "dp"
# This label is supossed to be right unter the header label(see the screens below to see my go to result created
# in photoshop)
header_date_label = MDLabel(text=date_of_publishing_text, size_hint_y=None, font_style="Caption", height="10dp")
widget_holder.add_widget(header_image)
widget_holder.add_widget(header_label)
widget_holder.add_widget(header_date_label)
for paragraph in paragraphs_text:
text_paragraph = MDLabel(text=paragraph, size_hint_y=None,
pos_hint={"center_x": .5}, halign="justify")
text_paragraph.height = str(len(text_paragraph.text)) + "dp"
widget_holder.add_widget(text_paragraph)
scroll_widget_holder.add_widget(widget_holder)
self.add_widget(scroll_widget_holder)
class TestApp(MDApp):
def build(self):
return RootWidget()
if __name__ == '__main__':
TestApp().run()
Upvotes: 0
Views: 1428
Reputation: 39092
You can calculate the height of the BoxLayout
yourself by just adding the heights of all its children (including padding
and spacing
). If you know (or set) the heights of the children as you add them during the update
method, you can just set the height using:
widget_holder.height = new_height
where new_height
is the above calculated sum. If you don't know the heights of the children, you can do something like:
def adjust_height(self, box, dt):
# this does not handle padding and spacing
new_height = 0
for child in box.children:
new_height += child.height
box.height = new_height
And you can call it at the end of your update()
method as:
Clock.schedule_once(partial(self.adjust_height, widget_holder))
Upvotes: 1