Kivy RecycleView 作为 ListView 的替代品?它是如何工作的?

Kivy RecycleView as an alternative to ListView? How does it work?

我应该先说明一下,我仍然是 Kivy 的新手。 我尝试寻找类似的问题,但它们要么已过时,要么不清楚。

我正在寻找可以显示元素列表的东西,其中可以使用 select 与其他小部件(按钮等)交互的东西。 我偶然发现必须使用 documentation page on ListView, but it clearly states that ListView is deprecated and RecycleView

现在的问题是关于如何使用 RecycleView 的文档似乎不是很清楚(至少对我而言)。它肯定比其他小部件更复杂,我似乎无法弄清楚。

将其分解为更容易理解的问题: 1. 如何定义充当项目列表的 RecycleView? 2.我如何为其提供物品? 3. 我如何与之交互,特别是关于一次只制作一个项目 select ,检测什么时候 selected 并在事件发生时自动制作一些 selected ?

哦,顺便说一下,我更喜欢尽可能使用 kv 语言。

如果能帮助我查找或理解文档资源,我将不胜感激,这些资源将使我能够更全面地理解这一点以供将来使用。我真的希望在某个地方有关于这些复杂功能的教程,但如果它存在,很难找到它。

下面的示例说明了如何使用 Recycleview 显示按钮列表,并且当每个按钮被选中时,它会显示一个弹出窗口 window。

例子

main.py

from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.properties import ListProperty, StringProperty, ObjectProperty


class MessageBox(Popup):

    def popup_dismiss(self):
        self.dismiss()


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout):
    """ Adds selection and focus behaviour to the view. """
    selected_value = StringProperty('')
    btn_info = ListProperty(['Button 0 Text', 'Button 1 Text', 'Button 2 Text'])


class SelectableButton(RecycleDataViewBehavior, Button):
    """ Add selection support to the Label """
    index = None

    def refresh_view_attrs(self, rv, index, data):
        """ Catch and handle the view changes """
        self.index = index
        return super(SelectableButton, self).refresh_view_attrs(rv, index, data)

    def on_press(self):
        self.parent.selected_value = 'Selected: {}'.format(self.parent.btn_info[int(self.id)])

    def on_release(self):
        MessageBox().open()


class RV(RecycleView):
    rv_layout = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'text': "Button " + str(x), 'id': str(x)} for x in range(3)]


class TestApp(App):
    title = "RecycleView Button Popup Demo"

    def build(self):
        return RV()


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

test.kv

#:kivy 1.10.0

<MessageBox>:
    title: 'Popup Message Box'
    size_hint: None, None
    size: 400, 400

    BoxLayout:
        orientation: 'vertical'
        Label:
            text: app.root.rv_layout.selected_value
        Button:
            size_hint: 1, 0.2
            text: 'OK'
            on_press:
                root.dismiss()

<SelectableButton>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (0.0, 0.9, 0.1, 0.3)
        Rectangle:
            pos: self.pos
            size: self.size

<RV>:
    rv_layout: layout
    viewclass: 'SelectableButton'
    SelectableRecycleBoxLayout:
        id: layout
        default_size: None, dp(56)
        default_size_hint: 0.1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: "vertical"

输出

我做了一个更简单的例子。在我的示例中,可以更改每行的布局,包括 class RecycleViewRow 中的小部件,使用 kv 语言。 作为示例,我已经在每行中放置了一个标签和一个按钮。 我希望这对您有所帮助。

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.popup import Popup

Builder.load_string('''
#:kivy 1.10.0
#: import Popup kivy.uix.popup

<MessageBox>:
    title: 'Popup Message Box'
    size_hint: None, None
    size: 400, 400

    BoxLayout:
        orientation: 'vertical'
        Label:
            text: root.message
        Button:
            size_hint: 1, 0.2
            text: 'OK'
            on_press: root.dismiss()

<RecycleViewRow>:
    orientation: 'horizontal'
    Label:
        text: root.text
    Button:
        text: 'Show'
        on_press: app.root.message_box(root.text)

<MainScreen>:
    viewclass: 'RecycleViewRow'
    RecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'                    
                    ''')

class MessageBox(Popup):
    message = StringProperty()

class RecycleViewRow(BoxLayout):
    text = StringProperty()   

class MainScreen(RecycleView):    
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.data = [{'text': "Button " + str(x), 'id': str(x)} for x in range(3)]

    def message_box(self, message):
        p = MessageBox()
        p.message = message
        p.open() 
        print('test press: ', message)

class TestApp(App):
    title = "RecycleView Direct Test"

    def build(self):
        return MainScreen()

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