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

KivyMD RecycleView网格布局中CheckBox点击状态重复触发问题

问题成因
  • RecycleView的核心逻辑是视图复用:它只会创建刚好覆盖屏幕可见区域的少量GridTile视图实例,当用户滑动列表时,会把滑出屏幕的旧视图直接复用给新滑入屏幕的条目。你当前的代码没有将CheckBox的选中状态和RecycleView绑定的data数据集做关联,视图复用时就会把旧视图上的CheckBox状态直接带到新条目上,看起来就是其他条目同步触发了选中/取消操作。
  • 你定义的data列表里只有tile字段,没有为每个条目预留存储选中状态的字段,无法在视图绑定时还原当前条目的正确选中状态,导致状态完全混乱。
修复步骤
  1. 给data数据集的每个条目新增is_checked字段,用来持久化存储对应条目的选中状态
  2. 给GridTile新增index属性,用来标记当前视图对应data列表的下标
  3. 调整CheckBox的active事件绑定逻辑,触发时更新data列表对应下标的is_checked值,同时在视图复用时主动根据data的is_checked值更新CheckBox状态
修复后完整可运行代码
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview import RecycleView
from kivy.properties import StringProperty, ListProperty, NumericProperty, BooleanProperty
from kivy.clock import Clock

from kivymd.app import MDApp
from kivymd.uix.imagelist import SmartTile
from kivymd.uix.selectioncontrol import MDCheckbox

Builder.load_string("""
<Check>:
    check_active: root.check_active
    on_check_active: self.check.active = root.check_active

<GridTile>:
    tile: root.tile
    index: root.index
    check_active: root.check_active
    SmartTile:
        source: root.tile
        size_hint_y: None
        height: '150dp'
        Check:
            check_active: root.check_active
            parent_index: root.index

<GridScreen>:
    name: 'grid_screen'
    RV:
        id: rv
        viewclass: 'GridTile'
        RecycleGridLayout:
            cols: 2
            size_hint_y: None
            default_size: 1, dp(150)
            default_size_hint: 1, None
            height: self.minimum_height
""")

class GridTile(Screen):
    tile = StringProperty('')
    index = NumericProperty(-1)
    check_active = BooleanProperty(False)

class GridScreen(Screen):
    pass

class RV(RecycleView):
    data = ListProperty([])

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.cell_data()

    def cell_data(self):
        self.data = [{"tile": 'The Beatles', "is_checked": False, "index": i} for i in range(41)]

class Check(SmartTile):
    check_active = BooleanProperty(False)
    parent_index = NumericProperty(-1)
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_once(self.add_checkbox)

    def add_checkbox(self, interval):
        app = MDApp.get_running_app()
        self.check = MDCheckbox(size_hint=(None, None), size=(48, 48), active=self.check_active)
        self.check.bind(active=self.on_check_active)
        self._box_overlay.add_widget(self.check)
    
    def on_check_active(self, checkbox, value):
        app = MDApp.get_running_app()
        if self.parent_index >= 0:
            app.root.get_screen('grid_screen').ids.rv.data[self.parent_index]['is_checked'] = value
        app.on_checkbox_active(checkbox, value, self.parent_index)

class ThisApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        self.sm = ScreenManager()
        self.sm.add_widget(GridScreen(name='grid_screen'))
        return self.sm

    def on_checkbox_active(self, checkbox, value, index):
        if value:
            print(f'第{index}个条目的checkbox', checkbox, 'is active', 'and', checkbox.state, 'state')
        else:
            print(f'第{index}个条目的checkbox', checkbox, 'is inactive', 'and', checkbox.state, 'state')

if __name__ == "__main__":
    ThisApp().run()

内容的提问来源于stack exchange,提问作者Henry Thornton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 05:06:00