Kivy 多列 RecyclerView

Kivy Multiple Column RecyclerView

我只是在玩 Pythonkivy ,我已经按照 kivy 官方文档将我的字符串数据加载到 RecyclerView 中。但是我在将 object 加载到列表中的多个列时遇到了麻烦,就像表单数据一样。例如,我想将姓名、姓氏和年龄分为三列,标题为 headers 逐行,我也尝试过 RecyclerGridLayout 有 3 列,但它可以只将姓名加载到网格中,而不管逐行要求

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

将感谢任何提示或示例代码以了解 RecyclerView 如何在 kivy

上工作

不要使用 Label 作为视图class,而是创建自定义 class。这可能是带有两个框的水平框布局。

<CustomClass@BoxLayout>:
    orientation: "horizontal"
    Label:
    Label:

我也在找这个,找不到具体的例子,所以我提供了我的解决方案。正如 el3ien 所说,您需要创建一个自定义 class 来代表您可选择标签的每一行。

<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
label1_text: 'label 1 text'  # I have included two methods of accessing the labels
label2_text: 'label 2 text'  # This is method 1
label3_text: 'label 3 text'
pos: self.pos
size: self.size
Label:
    id: id_label1  # method 2 uses the label id
    text: root.label1_text
Label:
    id: id_label2
    text: root.label2_text
Label:
    id: id_label3
    text: root.label3_text

在将数据应用到 RV 中时,您需要重组字典以反映标签布局

class RV(RecycleView):
def __init__(self, **kwargs):
    super(RV, self).__init__(**kwargs)
    paired_iter = zip(items_1, items_2)  # items_1 and items_2 are defined elsewhere
    self.data = []
    for i1, i2 in paired_iter:
        d = {'label2': {'text': i1}, 'label3': {'text': i2}}
        self.data.append(d)

最后在 refresh_view_attrs 中,您将指定绑定到每个标签的 .label_text,或者您可以使用标签 ID。

def refresh_view_attrs(self, rv, index, data):
    ''' Catch and handle the view changes '''
    self.index = index
    self.label1_text = str(index)
    self.label2_text = data['label2']['text']
    self.ids['id_label3'].text = data['label3']['text']  # As an alternate method of assignment
    return super(SelectableLabel, self).refresh_view_attrs(
        rv, index, data)

完整代码如下:

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.uix.gridlayout import GridLayout
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
    label1_text: 'label 1 text'
    label2_text: 'label 2 text'
    label3_text: 'label 3 text'
    pos: self.pos
    size: self.size
    Label:
        id: id_label1
        text: root.label1_text
    Label:
        id: id_label2
        text: root.label2_text
    Label:
        id: id_label3
        text: root.label3_text

<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
''')


items_1 = {'apple', 'banana', 'pear', 'pineapple'}
items_2 = {'dog', 'cat', 'rat', 'bat'}


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    ''' Adds selection and focus behaviour to the view. '''


class SelectableLabel(RecycleDataViewBehavior, GridLayout):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    cols = 3

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        self.label1_text = str(index)
        self.label2_text = data['label2']['text']
        self.ids['id_label3'].text = data['label3']['text']  # As an alternate method of assignment
        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)
        paired_iter = zip(items_1, items_2)
        self.data = []
        for i1, i2 in paired_iter:
            d = {'label2': {'text': i1}, 'label3': {'text': i2}}
            self.data.append(d)
        # can also be performed in a complicated one liner for those who like it tricky
        # self.data = [{'label2': {'text': i1}, 'label3': {'text': i2}} for i1, i2 in zip(items_1, items_2)]


class TestApp(App):
    def build(self):
        return RV()

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

我使用了@el3ien 的上述想法。我的代码如下。

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
Builder.load_string('''
<RV>:
    viewclass: 'myView'
    RecycleBoxLayout:
        default_size: None, dp(200)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'


<myView@BoxLayout>:
    BoxLayout:
        orientation: 'horizontal'


        BoxLayout:
            orientation: 'vertical'
            on_release:

            Button:
                size_hint: (1,1)
                background_normal: 'C:/Users/Arsalan/Desktop/dummyImage2.jpg'
                background_down: 'C:/Users/Arsalan/Desktop/dummyImage1.png'
                text: 
                text_size: self.size
                halign: 
                valign: 'middle'

            Label:
                size_hint: (1,0.3)
                text: 'Product summary'
                text_size: self.size 
                halign:
                valign: 'middle'
                canvas.before:
                    Color:
                        rgba: (0.6, 0.7, 0.4, 1)
                    Rectangle:
                        size: self.size
                        pos: self.pos
            BoxLayout:
                size_hint :(1,0.01)

            Label:
                size_hint: (1,0.3)
                text: 'Rs 600'
                text_size: self.size 
                halign:
                valign: 'middle'




        BoxLayout:
            orientation: 'vertical'
            size_hint: (0.001,1)




        BoxLayout:
            orientation: 'vertical'
            on_release:

            Button:
                size_hint: (1,1)
                background_normal: 'C:/Users/Arsalan/Desktop/dummyImage2.jpg'
                background_down: 'C:/Users/Arsalan/Desktop/dummyImage1.png'
                text: 
                text_size: self.size
                halign: 
                valign: 'middle'

            Label:
                size_hint: (1,0.3)
                text: 'Product summary'
                text_size: self.size 
                halign:
                valign: 'middle'
                canvas.before:
                    Color:
                        rgba: (0.6, 0.7, 0.4, 1)
                    Rectangle:
                        size: self.size
                        pos: self.pos
            BoxLayout:
                size_hint :(1,0.01)

            Label:
                size_hint: (1,0.3)
                text: 'Rs 600'
                text_size: self.size 
                halign:
                valign: 'middle'




''')
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()

尝试一下,如果您还有任何问题,请告诉我。

我想在 table 中添加 headers 行;而且,我正在尝试以下操作:

<RV>:
    BoxLayout:
        orientation: "vertical"

        BoxLayout:
            orientation: 'horizontal'
            size_hint: 1, None
            size_hint_y: None
            height: 25
            Label:
                text: "Item"
            Label:
                text: "User ID"
            Label:
                text: "User Name"

        BoxLayout:
            RecycleView:
                id: review
                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

但是随后 :SelectableRecycleBoxLayout 向层次结构中移动得更深,我不再得到 table,只有 headers...如何解决这个问题?我仍然不太明白如何从 python 获得 kv 的东西。 :-(