Python/KivyMD中RecycleView添加MDExpansionPanel报错及属性不生效问题
问题描述
无法在RecycleView的data变量中添加MDExpansionPanel对象。
首次实现版本(main.py)
from kivy.lang import Builder from kivy.uix.recycleview import RecycleView from kivymd.app import MDApp from kivymd.uix.expansionpanel import MDExpansionPanelOneLine Builder.load_string(""" <MyRecycleView>: viewclass: "MDExpansionPanel" effect_cls: "ScrollEffect" RecycleBoxLayout: default_size: None, dp(56) default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical' spacing: dp(10) """) class MyRecycleView(RecycleView): pass class MyApp(MDApp): def build(self): recycle = MyRecycleView() recycle.data = [ { "content":None, "icon":"arrow-right", "panel_cls":MDExpansionPanelOneLine( text="Test" ) } ] return recycle MyApp().run()
运行后抛出错误:
ValueError: KivyMD: `panel_cls` object must be must be one of the objects from the list [MDExpansionPanelOneLine, MDExpansionPanelTwoLine, MDExpansionPanelThreeLine]
第二次尝试(自定义面板版本)
尝试自定义继承自MDExpansionPanel的类,在类的panel_cls属性中预先配置MDExpansionPanelOneLine,同时新增StringProperty类型的text属性用于绑定给MDExpansionPanelOneLine的text属性,代码如下:
from kivy.lang import Builder from kivy.uix.recycleview import RecycleView from kivymd.app import MDApp from kivymd.uix.expansionpanel import MDExpansionPanel from kivy.properties import StringProperty Builder.load_string(""" #:import MDExpansionPanelOneLine kivymd.uix.expansionpanel.MDExpansionPanelOneLine <MyRecycleView>: viewclass: "MyExpansionPanel" effect_cls: "ScrollEffect" RecycleBoxLayout: default_size: None, dp(56) default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical' spacing: dp(10) <MyExpansionPanel>: content: None panel_cls: MDExpansionPanelOneLine(\ text=root.text ) """) class MyRecycleView(RecycleView): pass class MyExpansionPanel(MDExpansionPanel): text = StringProperty() class MyApp(MDApp): def build(self): recycle = MyRecycleView() recycle.data = [ { "icon":"arrow-right", "text":"Test" } ] return recycle MyApp().run()
该版本无运行报错,但MDExpansionPanelOneLine的text属性无法随RecycleView传入的参数更新,RecycleView data变量中配置的text属性不生效。
解决方案
问题核心原因有两点:
- 直接在RecycleView的data里传实例化的
panel_cls对象不符合KivyMD校验规则,panel_cls只接受类本身,不接受提前实例化的对象,这是第一个版本报错的直接原因。 - 第二个版本绑定不生效,是因为
MDExpansionPanel初始化时就会生成panel_cls对应的实例,kv里写的静态绑定不会在后续text属性更新时,同步到已经生成的面板头部组件上。
正确实现方式是重写自定义面板类的属性监听方法,在属性更新时主动修改面板头部的对应内容,完整可运行代码如下:
from kivy.lang import Builder from kivy.uix.recycleview import RecycleView from kivymd.app import MDApp from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelOneLine from kivy.properties import StringProperty Builder.load_string(""" <MyRecycleView>: viewclass: "MyExpansionPanel" effect_cls: "ScrollEffect" RecycleBoxLayout: default_size: None, dp(56) default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical' spacing: dp(10) <MyExpansionPanel>: content: None """) class MyRecycleView(RecycleView): pass class MyExpansionPanel(MDExpansionPanel): text = StringProperty() def __init__(self, **kwargs): self.panel_cls = MDExpansionPanelOneLine super().__init__(**kwargs) def on_text(self, instance, value): if self.panel_cls_instance: self.panel_cls_instance.text = value class MyApp(MDApp): def build(self): recycle = MyRecycleView() recycle.data = [ { "icon":"arrow-right", "text":"Test 1" }, { "icon":"arrow-right", "text":"Test 2" } ] return recycle MyApp().run()
如果需要使用TwoLine、ThreeLine类型的面板头,只需要替换self.panel_cls对应的类,再在属性监听方法里对应修改secondary_text、tertiary_text属性即可。
内容的提问来源于stack exchange,提问作者Hugo Cezar
相关产品推荐
相关产品推荐

