I've got a follow-up question on Is it possible to change font size in Recycleview widgets? (thank you John for your help over there).
I'm having a bunch of nested MDRecycleView
instances and I'd like to update their data, specifically font_size
. Updating font_size
in my original question turned out not to be so complicated because you have a reference to the actual MDRecycleView
to call the refresh_from_data()
method from. Now with the nested MDRecycleView
instances all defined inside the .kv file, I'm still able to "update" the data of all the instances but haven't found a way to obtain the references of nested MDRecycleView
instances to call their respected refresh_from_data()
method. I would also like to keep the current architecture where I have all the objects living inside a .kv file (string).
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import MDBoxLayout
kv = """
<Content>:
bg_color: app.theme_cls.primary_dark
item1: ''
item2: ''
font_size: '15dp'
MDGridLayout:
rows: 2
MDLabel:
id: firstLabelId
halign: 'center'
text: root.item1
font_size: root.font_size
MDLabel:
id: secondLabelId
halign: 'center'
md_bg_color: root.bg_color
text: root.item2
font_size: root.font_size
<DailyService>:
bg_color: app.theme_cls.primary_dark
day: ''
innerData: []
font_size: '15dp'
MDGridLayout:
rows: 2
MDLabel:
id: serviceId
halign: 'center'
text: root.day
font_size: root.font_size
MDRecycleView:
viewclass: 'Content'
id: statisticContentRecycleViewId
data: root.innerData
do_scroll_y: False
do_scroll_x: False
RecycleBoxLayout:
default_size_hint: 1, 1
orientation: 'vertical'
<MainScreen>:
name: 'mainScreen'
rvid: myRv
MDRelativeLayout:
orientation: 'vertical'
MDRecycleView:
viewclass: 'DailyService'
id: myRv
RecycleBoxLayout:
default_size: None, dp(200)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
MDSlider:
color: 'white'
orientation: 'horizontal'
size_hint: (0.2, 0.2)
pos_hint: {"x":0.4, "top": 1}
min: 10
value: 20
max: 30
on_value_normalized: root.fontSizeSlider(self.value)
MyScreenManager:
mainScreen: mainScreenId
MainScreen:
id: mainScreenId
"""
class Content(MDBoxLayout):
pass
class DailyService(MDBoxLayout):
pass
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def fontSizeSlider(self, value):
rv = self.ids.myRv
data = rv.data
for v in data:
v['font_size'] = str(int(value)) + 'dp'
'''
innerData = v['innerData']
for innerV in innerData:
innerV['font_size'] = str(int(value)) + 'dp'
### I believe the missing refresh_from_data() calls cause the issue
'''
rv.refresh_from_data()
class MyScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
class MyApp(MDApp):
def on_start(self):
data = []
for i in range(10):
innerData = []
for i in range(2):
innerData.append({'item1': 'ITEM1',
'item2': 'ITEM2'})
data.append({'day': 'DAY','innerData': innerData})
self.root.ids.mainScreenId.rvid.data = data
def build(self):
self.theme_cls.theme_style = 'Dark'
self.theme_cls.primary_palette = 'Blue'
self.theme_cls.accent_palette = 'Amber'
return Builder.load_string(kv)
if __name__ == '__main__':
MyApp().run()
The refresh_from_data()
method of a RecycleView
can be called directly, or it will be triggered when the data
of a RecyclView
is changed. Unfortunately, changing an individual item in one of the dicts in the data list is not enough to trigger the update. So, you can trigger the refresh_from_data()
method of the nested RecycleView
by forcing a change in its data
.
def fontSizeSlider(self, value):
rv = self.ids.myRv
data = rv.data
for v in data:
v['font_size'] = str(int(value)) + 'dp'
innerData = v['innerData']
new_inner = copy.deepcopy(innerData)
for innerV in new_inner:
innerV['font_size'] = str(int(value)) + 'dp'
v['innerData'] = new_inner # this will trigger a call to refresh_from_data on the nested RecycleView
rv.refresh_from_data()