我正在尝试创建一个简单的表,在RecycleView中选择一个项目选择整行。这已通过更改单击行上每个togglebutton的状态,通过其索引来解决。但是,如果我想手动将一些数据添加到我的recycleview中,然后使用refresh_from_data()方法更新表,则会导致一些奇怪的行为。 refresh_from_data()方法更改recycleview中按钮的索引。
通过使用index = 0更改togglebutton的状态,可以观察索引[0]如何在RecycleView的左上角和RecycleView的右下角之间切换。我的代码说明了这一点。只要按下任何按钮,我就将index [0]设置为等于'down'。
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):
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
print('======================')
print(' Add some data ')
print('======================')
# See how index[0] changes between the refresh()
rgl.children[0].state = "down"
root = App.get_running_app().root
root.refresh_from_data()
KV = '''
<MyButton>:
on_release:
app.root.find_row(self)
TestRecycleView:
data: [{'text': str(x)} if x not in range(9,12) else {'text': 'Press here'} for x in range(21)]
viewclass: 'MyButton'
id: rv_controller
target_id: None
RecycleGridLayout:
id: gl
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()
我得出结论,索引在0,1,2,3 ....和end,end-1,end-2之间切换,...意味着所选行在每个按钮之间的中间行上“镜像”按。
但是为什么RecycleView会以这种方式运行,我该怎么做呢?我想做的就是能够一键选择整行,手动添加/更改数据,我也只想在任何给定时间选择一行。
但是refresh_from_data()方法让我很难做到。
我认为略有不同的方法会更好。不是设置特定按钮的state
,而是将state
属性添加到数据中,并更改数据中的state
。这样,RecycleView
将根据数据设置状态,并且按钮的交换无关紧要。所以在kv
中,将数据更改为:
TestRecycleView:
data: [{'text': str(x), 'state': 'normal'} for x in range(21)]
并将find_row()
更改为:
def find_row(self, instance):
self.selected_row = instance.index // self.items_per_row + 1
start_index = (self.selected_row - 1) * self.items_per_row
for index in range(start_index, start_index + self.items_per_row):
self.data[index]['state'] = 'down' # change data, not button state
self.refresh_from_data()