You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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属性不生效。


解决方案

问题核心原因有两点:

  1. 直接在RecycleView的data里传实例化的panel_cls对象不符合KivyMD校验规则,panel_cls只接受类本身,不接受提前实例化的对象,这是第一个版本报错的直接原因。
  2. 第二个版本绑定不生效,是因为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:03:27