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"