在Kivy RecycleView中调用scroll_to方法报错:'function'无'is_triggered'属性
解决RecycleView中scroll_to报错'function' object has no attribute 'is_triggered'的问题
问题原因
- 直接访问RecycleBoxLayout的
children属性不可靠:RecycleView采用视图回收复用机制,children中的元素数量远少于data的数量,你拿到的children[0]不一定对应第一个数据项的视图,甚至可能是已被回收的无效视图。 scroll_to方法使用错误:RecycleView的scroll_to需要传入当前RecycleView管理的有效视图实例,直接传入children中的元素会因为视图未正确绑定滚动触发器,导致内部调用时出现is_triggered属性不存在的错误。- 直接修改视图样式无效:RecycleView的视图由
data驱动,直接修改视图属性会被后续的视图复用覆盖,应该修改data中的对应字段来更新样式。
解决方案
- 放弃使用
scroll_to,直接通过设置scroll_y属性控制滚动位置:垂直方向上,scroll_y=1表示滚动到顶部(第一个数据项),scroll_y=0表示滚动到底部(最后一个数据项)。 - 通过修改
data中的字段更新视图样式,调用refresh_from_data()触发视图刷新。 - 修正Card的高度设置,避免循环引用问题。
修改后的完整代码
from kivy.lang import Builder from kivy.clock import Clock from kivymd.uix.card import MDCard from kivymd.app import MDApp from kivy.properties import NumericProperty from kivy.uix.recycleview import RecycleView KV = ''' <Card>: size_hint_y: None height: dp(200) # 修正高度设置,避免循环引用 md_bg_color: .4,.6,.4,.8 MDScreen: MDBoxLayout: orientation: "vertical" spacing: dp(0) MDBoxLayout: id: coll size_hint_y: None height: dp(2) ScrolView: id: g viewclass: "Card" RecycleBoxLayout: id: box spacing: dp(10) default_size: None, self.parent.height - dp(40) # 引用父容器高度 default_size_hint: 1, None size_hint_y: None height: self.minimum_height orientation: 'vertical' ''' class Card(MDCard): pass class ScrolView(RecycleView): name = NumericProperty() scroll_moved = None def on_touch_down(self,touch): if self.collide_point(*touch.pos): touch.grab(self) return super(ScrolView, self).on_touch_down(touch) def on_touch_move(self,touch): if touch.grab_current is self: self.scroll_moved = True return super(ScrolView, self).on_touch_move(touch) def on_touch_up(self,touch): if touch.grab_current is self: if self.scroll_moved: if touch.y > self.height // 2: try: # 滚动到顶部(第一个数据项) self.scroll_y = 1 if self.data: # 重置所有卡片的背景色 for item in self.data: item["md_bg_color"] = (.4,.5,.7,1) # 设置第一个卡片为红色 self.data[0]["md_bg_color"] = (1,0,0,1) # 设置最后一个卡片为蓝色 self.data[-1]["md_bg_color"] = (0,0,1,1) # 刷新视图 self.refresh_from_data() except Exception as e: print(e) self.scroll_moved = False touch.ungrab(self) return super(ScrolView, self).on_touch_up(touch) class Example(MDApp): def build(self): return Builder.load_string(KV) def on_start(self): for i in range(4): self.root.ids.g.data.append({"md_bg_color": (.4,.5,.7,1), "name": i}) Example().run()
额外说明
- 如果需要滚动到指定索引的数据项,可通过计算
scroll_y的值实现:scroll_y = 1 - (index / (len(self.data) - 1))(假设每个视图高度相同)。 - 永远不要直接修改RecycleView的
children元素属性,所有视图更新都应该通过修改data来完成,这是RecycleView的核心设计原则。
内容的提问来源于stack exchange,提问作者Shoeman
相关产品推荐
相关产品推荐

