RecycleView¶
在 1.10.0 版本加入.
RecycleView 提供了一种灵活的模型,用于查看大型数据集的选定部分。其目的在于避免因生成大量控件以显示众多数据项而可能导致的性能下降。
警告
由于 RecycleView 会复用控件,因此对单个控件的任何状态更改都会在复用时保留在该控件上,即使 RecycleView 分配给它的 data 发生了变化,除非在 data 中跟踪了完整状态(见下文)。
视图通过处理 viewclass 的实例。其设计基于 MVC(模型-视图-控制器)模式。
模型:模型由您通过字典列表传入的
data构成。视图:视图在布局和视图之间进行拆分,并通过适配器实现。
控制器:控制器决定逻辑交互,由
RecycleViewBehavior实现。
这些是抽象类,不能直接使用。默认的具体实现包括:模型使用 RecycleDataModel,视图使用 RecycleLayout,控制器使用 RecycleView。
当实例化RecycleView时,它会自动创建视图和数据类。然而,必须手动创建布局类并将其添加到RecycleView中。
当作为RecycleView的子组件添加时,会自动创建一个布局管理器作为:attr:~RecycleViewBehavior.layout_manager。同样,在移除时也会如此。一个要求是,布局管理器必须作为子组件包含在RecycleView的控件树中的某个位置,以便能够找到视口。
一个最小示例可能如下所示:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
Builder.load_string('''
<RV>:
viewclass: 'Label'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(100)]
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
为了在视图中支持选择功能,您可以按如下方式添加所需的行为:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
Builder.load_string('''
<SelectableLabel>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
''')
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behavior to the view. '''
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
else:
print("selection removed for {0}".format(rv.data[index]))
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(100)]
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
请参阅 examples/widgets/recycleview/basic_data.py 文件,以获取更完整的示例。
Viewclass 状态¶
由于 RecycleView 会根据需要重用或实例化 viewclass 控件,因此控件的顺序和内容是可变的。所以,对单个控件的任何状态更改都会保留在该控件上,即使从 data 字典分配给它的数据发生变化,除非 data 跟踪这些更改,或者在重用时手动刷新它们。
在viewclass控件中管理状态变化有两种方法:
将状态存储在RecycleView.data模型中。
通过捕获
data的更新并手动刷新,即时生成状态变化。
示例:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.properties import BooleanProperty, StringProperty
Builder.load_string('''
<StatefulLabel>:
active: stored_state.active
CheckBox:
id: stored_state
active: root.active
on_release: root.store_checkbox_state()
Label:
text: root.text
Label:
id: generate_state
text: root.generated_state_text
<RV>:
viewclass: 'StatefulLabel'
RecycleBoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class StatefulLabel(RecycleDataViewBehavior, BoxLayout):
text = StringProperty()
generated_state_text = StringProperty()
active = BooleanProperty()
index = 0
'''
To change a viewclass' state as the data assigned to it changes,
overload the refresh_view_attrs function (inherited from
RecycleDataViewBehavior)
'''
def refresh_view_attrs(self, rv, index, data):
self.index = index
if data['text'] == '0':
self.generated_state_text = "is zero"
elif int(data['text']) % 2 == 1:
self.generated_state_text = "is odd"
else:
self.generated_state_text = "is even"
super(StatefulLabel, self).refresh_view_attrs(rv, index, data)
'''
To keep state changes in the viewclass with associated data,
they can be explicitly stored in the RecycleView's data object
'''
def store_checkbox_state(self):
rv = App.get_running_app().rv
rv.data[self.index]['active'] = self.active
class RV(RecycleView, App):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': str(x), 'active': False} for x in range(10)]
App.get_running_app().rv = self
def build(self):
return self
if __name__ == '__main__':
RV().run()
- 待办事项:
清除缓存类实例的方法。
测试当视图无法找到时的情况(例如,viewclass 为 None)。
修复选择跳转。
警告
当视图被复用时,如果数据保持不变,它们可能不会触发更新。
- class kivy.uix.recycleview.RecycleView(**kwargs)[源代码]¶
基类:
RecycleViewBehavior,ScrollViewRecycleView 是一个灵活的视图,用于在大数据集中提供一个有限的窗口。
请参阅模块文档以获取更多信息。
- add_widget(widget, *args, **kwargs)[源代码]¶
将此小部件添加为当前小部件的子级。
- 参数:
- widget:
Widget 要添加到我们子控件列表中的控件。
- index:整数,默认值为0
在列表中插入小部件的索引。请注意,默认值为0意味着小部件被插入到列表的开头,因此会绘制在其他同级小部件之上。关于索引和小部件层次结构的完整讨论,请参阅 小部件编程指南。
在 1.0.5 版本加入.
- canvas:字符串,默认为 None
用于添加控件画布的Canvas。可以是'before'、'after'或None(默认画布)。
在 1.9.0 版本加入.
- widget:
>>> from kivy.uix.button import Button >>> from kivy.uix.slider import Slider >>> root = Widget() >>> root.add_widget(Button()) >>> slider = Slider() >>> root.add_widget(slider)
- data¶
当前视图适配器使用的数据。这是一个字典列表,其键映射到
viewclass的相应属性名称。data 是一个
AliasProperty,用于获取和设置生成视图所用的数据。
- key_viewclass¶
key_viewclass 是一个
AliasProperty,用于获取和设置当前layout_manager的键视图类。
- remove_widget(widget, *args, **kwargs)[源代码]¶
从该部件的子部件中移除一个部件。
- 参数:
- widget:
Widget 要从我们的子控件列表中移除的控件。
- widget:
>>> from kivy.uix.button import Button >>> root = Widget() >>> button = Button() >>> root.add_widget(button) >>> root.remove_widget(button)
- viewclass¶
当前 layout_manager 所使用的视图类。
viewclass 是一个
AliasProperty,用于获取和设置在视图中呈现的各个项目所生成的类。
- class kivy.uix.recycleview.RecycleViewBehavior(**kwargs)[源代码]¶
基类:
objectRecycleViewBehavior 提供了一种行为模型,基于此模型构建了
RecycleView。两者共同提供了一种可扩展且灵活的方式,用于在大型数据集上生成具有有限窗口的视图。请参阅模块文档以获取更多信息。
- data_model¶
负责维护数据集的数据模型。
data_model 是一个
AliasProperty,用于获取和设置当前的数据模型。
- layout_manager¶
负责在
RecycleView中定位视图的布局管理器。layout_manager 是一个
AliasProperty,用于获取和设置 layout_manager。
- refresh_from_data(*largs, **kwargs)[源代码]¶
当数据发生变化时,应调用此方法。数据变化通常意味着由于源数据已改变,所有内容都应重新计算。
该方法自动绑定到
RecycleDataModelBehavior类的on_data_changed方法上,因此会响应并接受该事件的关键字参数。可以手动调用以触发更新。
- view_adapter¶
负责提供视图中代表数据集中项目的适配器。
view_adapter 是一个
AliasProperty,用于获取和设置当前的视图适配器。
- RecycleView 数据模型
- RecycleView 布局
LayoutChangeExceptionLayoutSelectionBehaviorRecycleLayoutManagerBehaviorRecycleLayoutManagerBehavior.compute_visible_views()RecycleLayoutManagerBehavior.get_view_index_at()RecycleLayoutManagerBehavior.goto_view()RecycleLayoutManagerBehavior.key_viewclassRecycleLayoutManagerBehavior.refresh_view_layout()RecycleLayoutManagerBehavior.set_visible_views()RecycleLayoutManagerBehavior.viewclass
- RecycleView 视图
RecycleDataAdapterRecycleDataAdapter.attach_recycleview()RecycleDataAdapter.create_view()RecycleDataAdapter.detach_recycleview()RecycleDataAdapter.get_view()RecycleDataAdapter.get_visible_view()RecycleDataAdapter.invalidate()RecycleDataAdapter.make_view_dirty()RecycleDataAdapter.make_views_dirty()RecycleDataAdapter.recycleviewRecycleDataAdapter.refresh_view_attrs()RecycleDataAdapter.refresh_view_layout()RecycleDataAdapter.set_visible_views()
RecycleDataViewBehaviorRecycleKVIDsDataViewBehavior