Search code examples
pythonkivykivymd

Is it possible to change font size in Recycleview widgets?


I'm having a recycleview of labels and I would like to change the font size of these labels using MDSlider. I'm not sure if this is even possible. The closest thing I've got is to change the font of the objects retrieved by the method view_adapter.get_visible_view(index), which are the objects currently visible if I'm not mistaken. But using the code below which should be doing just that, I'm getting strange behavior as it's changing the font size of all visible labels, but also some of the labels which aren't visible.

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 = """
<DailyService>:
    bg_color: app.theme_cls.primary_dark
    day: ''
    service: ''
    
    MDGridLayout:
        rows: 2
        MDLabel:
            id: firstLabelId
            halign: 'center'
            text: root.day

        MDLabel:
            id: secondLabelId
            halign: 'center'
            md_bg_color: root.bg_color
            text: root.service
    
<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 DailyService(MDBoxLayout):
    pass

class MainScreen(Screen):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

    def fontSizeSlider(self, value):
        recycleViewObj = self.ids['myRv']
        index = 0
        while (recycleViewObj.view_adapter.get_visible_view(index)):
            idList = recycleViewObj.view_adapter.get_visible_view(index).ids
            for obj in idList.values():
                obj.font_size = str(int(value))+'dp'
            index = index + 1

    
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):
            data.append({'day': 'DAY','service': 'SERVICE'})
        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()

I've also tried using layout_manager along with the view_adapter and it seems to me that I'm able to extract all the objects from the Recycleview, but when attempting to change the font_size nothing happens. So my guess would be that those objects aren't actual objects that I see in my app. Here's the attempt:

def fontSizeSlider(self, value):
    recycleViewObj = self.ids['myRv']
    opts = recycleViewObj.layout_manager.view_opts
    for i in range(len(recycleViewObj.data)):
        viewAdapter = recycleViewObj.view_adapter
        viewClass = opts[i]['viewclass']
        data = recycleViewObj.data[i]
        dailyService = viewAdapter.get_view(i, data, viewClass)
        for obj in dailyService.ids.values():
            print(obj)
            obj.font_size = str(int(value))+'dp'

Is it possible to achieve what I want with Recycleview? Just to make myself clear, I would like to change the font of all the labels in the Recycleview (not just visible ones).


Solution

  • You can add a font_size property to your DailyService class, and use it to define the font_size of the Labels:

    <DailyService>:
        bg_color: app.theme_cls.primary_dark
        day: ''
        service: ''
        font_size: '15dp'
    
        MDGridLayout:
            rows: 2
            MDLabel:
                id: firstLabelId
                halign: 'center'
                text: root.day
                font_size: root.font_size
    
            MDLabel:
                id: secondLabelId
                halign: 'center'
                md_bg_color: root.bg_color
                text: root.service
                font_size: root.font_size
    

    Then in your fontSizeSlider() method, update the font_size in the data of the MDRecycleView instance:

    def fontSizeSlider(self, value):
        rv = self.ids.myRv
        data = rv.data
        for v in data:
            v['font_size'] = str(int(value)) + 'dp'
        rv.refresh_from_data()