如何使用 Kivy select RecycleView 中的整行

How to select entire row in RecycleView using Kivy

我是 python 的新手,但完全是 Kivy 的初学者。我发现围绕 Kivy 的文档很难解释,至少对我来说是这样。到目前为止,我已经能够创建一个 RecycleView,我可以在其中添加、删除和更改数据。理想情况下,我希望能够拥有任意数量的列,但每一行上的所有数据都属于一起。因此,如果我 select 一个,我想突出显示该行中的所有项目。我试过使用 togglebutton 但没有成功。我只是不知道如何通过 ID 或其他方法访问 RecycleView 中的每个单独的切换按钮。如果我可以单独访问每个切换按钮,我可以简单地将其状态更改为等于“向下”。到目前为止,我只能找到用户 select 编辑了哪一行(但不是那么优雅)。我通过计算每行的按钮数量并将其与 selected 按钮的索引进行比较来管理这一点。

这是我正在试验的一个例子,通常我更喜欢使用 .kv 文件:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.recycleview.views import RecycleDataViewBehavior


class MyButton(RecycleDataViewBehavior, ToggleButton):
    index = None

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


class TestRecycleView(RecycleView):
    items_per_row = 3
    selected_data = None
    selected_row = None

    def find_row(self, instance):
        self.selected_row = instance.index // self.items_per_row + 1
        print('Row: ', self.selected_row)
        self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
                                       * self.selected_row]
        print('Data: ', self.selected_data)


KV = '''

<MyButton>:
    on_release:
        app.root.find_row(self)

TestRecycleView:
    data: [{'text': str(x)} for x in range(21)]
    viewclass: 'MyButton'
    id: rv_controller
    target_id: None
    RecycleGridLayout:
        cols: 3
        default_size_hint: 1, None
        orientation: 'vertical'
        key_selection: 'selectable'
        default_size: None, dp(26)
        size_hint_y: None
        height: self.minimum_height
        multiselect: True
        touch_multiselect: True

'''


class Test(App):
    def build(self):
        root = Builder.load_string(KV)
        # root.data = items
        return root


Test().run()

因为我已经能够计算出用户 selected 了哪一行,所以我还可以计算 RecycleView 中正在被 selected 的数据。但是,我想要这种行的简洁视觉表示 selection.

非常感谢您的帮助。

您可以在 find_row() 方法中添加 hack 来设置一行中所有按钮的状态。此方法将它们设置为与所选 Button 实例的状态一致,因此您也可以取消选择。

def find_row(self, instance):
    rgl = self.ids.gl
    num_buttons = len(rgl.children)
    num_rows = num_buttons // self.items_per_row
    self.selected_row = instance.index // self.items_per_row + 1
    print('Row: ', self.selected_row)
    self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
                                   * self.selected_row]
    print('Data: ', self.selected_data)
    index1 = (num_rows - self.selected_row + 1) * self.items_per_row - 1
    index2 = index1 - self.items_per_row
    state = instance.state
    for index in range(index1, index2, -1):
        rgl.children[index].state = state

这还需要将RecycleGridLayout的id设置为:

id: gl

ButtonsRecycleGridLayout的children,所以可以用来得到Buttons的总数。 children 列表中的索引与您的预期相反。即标记为 0Button 是索引 20,标记为 20Button 是索引 0。因此 index1 的计算使用该知识来确定所选行中 left-most Button 的索引。然后所选行中的 right-most Button 将是 index - 2range(inde1, index2, -1) 遍历所选行中的 Buttons。由于find_row()被称为on_releaseinstancestate已经被切换,所以它的state可以用来设置state的该行中的另一个 Buttons