I'm working with multiple columns in RecycleView
. For the sake of simplification, the following example contains only a ref
column which I expect to be displayed on one line and a message
column that should take the rest of the screen, the text being wrapped in order to be fully readable. Both columns are implemented using MDLabel
instances:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from random import randrange
from loremipsum import get_sentences
Builder.load_string('''
<RVLayout>:
spacing: 2
size_hint: None, None
height: message.texture_size[1]
MDLabel:
size_hint_x: None # label width should fit text
halign: 'center'
text: root.ref
md_bg_color: app.theme_cls.bg_darkest
MDLabel:
id: message
text: root.message
md_bg_color: app.theme_cls.bg_darkest
<RV>:
viewclass: 'RVLayout'
RecycleBoxLayout:
spacing: 2
default_size: None, dp(10)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class RVLayout(BoxLayout):
ref = StringProperty()
message = StringProperty()
def on_size(self, *args):
self.height = self.ids.message.texture_size[1]
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [
{
'ref': str(x).zfill(8),
'message': ' '.join(get_sentences(randrange(1, 4)))
} for x in range(50)]
class TestApp(MDApp):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
As you can see, I wrote an on_size
method to my RVLayout
so that everything looks well on resize (desktop case):
The height of the message
elements fits perfectly for any window width, while the width of ref
stays the same:
Now here comes my issue, when I start my app with a density > 1, the ref
column width is still the same even though the font is bigger. For instance with the environment variable KIVY_METRICS_DENSITY=2
I get the following:
How can I make ref
width adapt to the density?
Using adaptive size like suggested by @JohnAnderson put me on the right track. The sole problem is that the size is adapted on x and y axis. Thus the ref
labels are not the same height as the message
ones, which doesn't look great:
Playing with size_hint_y
and size_y
didn't help until I switched from BoxLayout
to GridLayout
and set size_hint_y: root.height
:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.recycleview import RecycleView
from kivy.uix.gridlayout import GridLayout
from kivymd.uix.label import MDLabel
from random import randrange
from loremipsum import get_sentences
Builder.load_string('''
<RVLayout>:
cols: 2
spacing: 2
size_hint: None, None
height: message.texture_size[1]
MDLabel:
adaptive_size: True
size_hint_y: root.height
padding_x: dp(5)
halign: 'center'
text: root.ref
md_bg_color: app.theme_cls.bg_darkest
MDLabel:
id: message
text: root.message
md_bg_color: app.theme_cls.bg_darkest
<RV>:
viewclass: 'RVLayout'
RecycleBoxLayout:
spacing: 2
default_size: None, dp(10)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class RVLayout(GridLayout):
ref = StringProperty()
message = StringProperty()
def on_size(self, *args):
self.height = self.ids.message.texture_size[1]
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [
{
'ref': str(x).zfill(8),
'message': ' '.join(get_sentences(randrange(1, 4)))
} for x in range(50)]
class TestApp(MDApp):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
pos_hint
isn't needed anymore in this case.
Now things look great for any density:
density==1
:
density==2
:
Edit: using adaptive_width: True
with BoxLayout works too