from
kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty
from kivy.uix.label import Label
import random
"""
This example extends a simple example of a RecycleView to add the use of the key_size
and dynamically changing the height of the widget based on the texture_size.
"""
kv = '''
<TwoButtons>:
# This class is used as the viewclass in the RecycleView
# The means this widget will be instanced to view one element of data from the data list.
# The RecycleView data list is a list of dictionaries. The keys in the dictionary specify the
# attributes of the widget.
size_hint_y: None
# size of the layout based on the key_size
Button:
text: root.left_text
text_size: self.width, None
valign: 'center'
halign: 'center'
on_release: print(f'Button {self.text} pressed')
Button:
text: root.right_text
on_release: print(f'Button {self.text} pressed')
BoxLayout:
orientation: 'vertical'
Button:
size_hint_y: None
height: 48
text: 'Add widget to RV list'
on_release: rv.add()
RV: # A Reycleview
id: rv
viewclass: 'TwoButtons' # The view class is TwoButtons, defined above.
data: self.rv_data_list # the data is a list of dicts defined below in the RV class.
scroll_type: ['bars', 'content']
bar_width: 10
RecycleBoxLayout:
# This layout is used to hold the Recycle widgets
orientation: 'vertical'
default_size: None, dp(48) # This sets the height of the BoxLayout that holds a TwoButtons instance.
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height # To scroll you need to set the layout height.
key_size: 'vc_size' # setting the key size
'''
class TwoButtons(BoxLayout): # The viewclass definitions, and property definitions.
left_text = StringProperty()
right_text = StringProperty()
class RV(RecycleView):
rv_data_list = ListProperty() # A list property is used to hold the data for the recycleview, see the kv code
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.rv_data_list = [{'left_text': f'Left {i}', 'right_text': f'Right {i}',
'vc_size': (48, 48)} for i in range(2)]
# This list comprehension is used to create the data list for this simple example.
# The data created looks like:
# [{'left_text': 'Left 0', 'right_text': 'Right 0'}, {'left_text': 'Left 1', 'right_text': 'Right 1'},
# {'left_text': 'Left 2', 'right_text': 'Right 2'}, {'left_text': 'Left 3'},...]
# notice the keys in the dictionary correspond to the kivy properties in the TwoButtons class.
# The data needs to be in this kind of list of dictionary formats. The RecycleView instances the
# widgets, and populates them with data from this list. Note the vc_size has been added to this list of
# dictionaries.
def add(self):
"""
Add a button to the rv_data_list, with random sized text string for the left button. Use the
texture_size of the left button to set the height of the viewclass widget
"""
i = len(self.rv_data_list)
r = random.randint(1, 50)
left_text = f'Added Left {i} ' * r
# calculate the texture_size of the text. Use a Label.
size = self.update_texture_size(left_text)
self.rv_data_list.extend(
[{'left_text': left_text, 'right_text': f'Added Right {i}',
'vc_size': size}])
def update_texture_size(self, text):
"""
Updates the texture size given for the width of the RV
:param text: The text to render
:return: The texture size
"""
width = self.width / 2 # the left label is 1/2 with width of the RV
# The created Label matches the dimensions of the button
temp_label = Label(text=text, size_hint_x=None, width=width,
text_size=(width, None), padding=10)
temp_label.texture_update() # update the texture_size
return temp_label.texture_size
def on_width(self, obj, value):
# when the width of the RV updates, recalculate the texture_sizes
for i, item in enumerate(self.rv_data_list):
size = self.update_texture_size(item['left_text'])
self.rv_data_list[i]['vc_size'] = size
self.refresh_from_data() # force an update
class RVTwoApp(App):
def build(self):
return Builder.load_string(kv)
RVTwoApp().run()