I am trying to create a stack of multiline Labels on Kivy inside a BoxLayout. How do I get the BoxLayout to expand according to its contents? Now the BoxLayout is squeezing the Labels instead.
I do not wish to hardcode the multiline Label size as I want each to be flexible to accommodate varying lines of text.
My demo code is as follows:
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.gridlayout import GridLayout from kivy.uix.scrollview import ScrollView from kivy.uix.label import Label from kivy.graphics import Color, Rectangle class MyApp(App): def build(self): self.root = GridLayout(rows=1) self.root.add_widget(Scroller()) return self.root class Scroller(ScrollView): def __init__(self): ScrollView.__init__(self) self.view = GridLayout(cols=1, size_hint=(1, None)) self.add_widget(self.view) self.view.bind(minimum_height=self.view.setter("height")) for i in range(20): self.view.add_widget(MyWidget(i % 2 is 1)) class MyWidget(BoxLayout): def __init__(self, odd, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" self.size_hint = (1, None) self.odd = odd for i in range(3): ll = Label(text=f"I am linenNumber {i + 1}") self.add_widget(ll) self.bind(pos=self.format_background_color) self.bind(size=self.format_background_color) def format_background_color(self, *args): with self.canvas.before: if self.odd: Color(0.0, 0.0, 0.2, mode="rgb") else: Color(0.0, 0.0, 0.8, mode="rgb") Rectangle(pos=self.pos, size=self.size) MyApp().run()
Advertisement
Answer
If the Label
s you added to MyWidget
have fixed amount of text
you can just set a specific value for MyWidget
‘s height
as self.height = "150dp"
(Adjust to your need).
Otherwise if you want the MyWidget
‘s height
enough to contain its children (here, Label
s) then set it to its minimum_height
. Also you have to set each Label
‘s height
to its texture height.
Thus your modified MyWidget
class should now look like,
class MyWidget(BoxLayout): def __init__(self, odd, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" self.size_hint_y = None self.odd = odd self.bind( pos = self.format_background_color, size = self.format_background_color, minimum_height = self.setter("height") ) for i in range(3): ll = Label(text=f"I am linenNumber {i + 1}") ll.bind(texture_size=self.resize_label) self.add_widget(ll) def resize_label(self, instance, value): instance.size_hint_y = None instance.height = value[1] ...
You can also utilize padding
and spacing
as,
class MyWidget(BoxLayout): def __init__(self, odd, **kwargs): super().__init__(**kwargs) self.orientation = "vertical" self.size_hint_y = None self.padding = "10dp" self.spacing = "10dp" ...