我正在尝试构建一个函数来帮助用户选择/取消选择 RecycleView 中的所有视图类实例。
问题是,虽然我可以将 RecycleView 中每个视图类的“selected”属性更改为 True 或 False。
例如这样:
for viewclass in recycle_view.data:
viewclass['selected'] = False
-视图类的“选定”颜色不会自行更新,这意味着它保留“选定”颜色,即使它在技术上是未选定的。 我想知道如何以某种方式刷新回收视图,它也考虑了视图类的颜色。
这是处理 vieclasses“UserCard”创建的代码,及其所有选择方法:
class UserCard(RecycleDataViewBehavior, MDBoxLayout):
selected_cards = False
name = StringProperty()
price = StringProperty()
date = StringProperty()
category = StringProperty()
callback = ObjectProperty(lambda x: x)
rview = ObjectProperty()
index = None
current_card_index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
selected_list_cards = []
selected_list_index = []
num_selected_cards = 0
color_normal = (18/250, 18/250, 18/250, 1)
color_select = (25/250, 25/250, 25/250, 1)
def refresh_view_attrs(self, rv, index, data):
self.index = index
self.selected = data["selected"]
return super().refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
if super().on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
Clock.schedule_once(self.callback)
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
self.selected = is_selected
rv.data[index]["selected"] = is_selected
screen_products = MDApp.get_running_app().root.get_screen('float_layout_products')
if is_selected:
rv.data[index]['md_bg_color'] = (25/250, 25/250, 25/250, 1)
if index not in UserCard.selected_list_index:
UserCard.selected_list_index.append(index)
UserCard.current_card_index = index
if index not in UserCard.selected_list_cards:
UserCard.selected_list_cards.append(self)
else:
rv.data[index]['md_bg_color'] = (18/250, 18/250, 18/250, 1)
if index in UserCard.selected_list_index:
UserCard.selected_list_index.remove(index)
if index in UserCard.selected_list_cards:
UserCard.selected_list_cards.remove(self)
screen_products.ids.items_selected.text = str(
len(UserCard.selected_list_index))
def on_tap_card(self, *args):
screen_products = MDApp.get_running_app().root.get_screen('float_layout_products')
recycle_view = screen_products.ids.recycle_view
datas = [data["selected"] for data in recycle_view.data]
if True in datas and not UserCard.selected_cards:
screen_products.switch_topbar_select()
UserCard.selected_cards = True
else:
if len(list(set(datas))) == 1 and not list(set(datas))[0]:
UserCard.selected_cards = False
for index, is_selected in enumerate(datas):
num_selected_cards = datas.count(True)
if num_selected_cards == 1 and is_selected:
UserCard.selected_cards = True
screen_products.ids.action_button_bottom.icon = 'pencil'
screen_products.on_edit_true()
elif num_selected_cards == 0 and not is_selected:
UserCard.selected_cards = False
elif num_selected_cards > 1 and is_selected:
# UserCard.selected_cards = False
screen_products.ids.action_button_bottom.icon = 'plus'
screen_products.on_edit_false()
if not UserCard.selected_cards:
screen_products.ids.action_button_bottom.icon = 'plus'
screen_products.on_edit_false()
screen_products.switch_topbar_search()
num_selected_cards = 0
def load_usercards_products(self):
screen_products = MDApp.get_running_app().root.get_screen('float_layout_products')
recycle_view = screen_products.ids.recycle_view
visual_path = fr'C:\Python\Projects\MyApp\saved_products\visuals\saved_visuals'
input_dir = 'C:/Python/Projects/MyApp/saved_products/inputs/'
input_files = [f for f in os.listdir(
input_dir) if os.path.isfile(os.path.join(input_dir, f))]
num_inputs = len(input_files)
creation_date_list = []
title_list = []
price_list = []
category_list = []
screen_products.ids.action_button_bottom.icon = 'plus'
async def generate_card():
recycle_view.data = []
for filename in os.listdir(visual_path):
if filename.endswith('.json'):
file_path = os.path.join(visual_path, filename)
with open(file_path, 'r') as f:
data = json.load(f)
creation_date = data['creation_date']
creation_date_list.append(creation_date)
title = data['title_text']
title_list.append(title)
price = data['price_value']
price_list.append(price)
category = data['category_value']
category_list.append(category)
for i in range(num_inputs):
await asynckivy.sleep(0)
recycle_view.data.append(
{
"name": title_list[i],
"price": price_list[i],
"date": creation_date_list[i],
"category": category_list[i],
"selected": False,
"callback": UserCard.on_tap_card,
}
)
Clock.schedule_once(lambda x: asynckivy.start(generate_card()))
这些是 UserCard- 和 recycle_view 类。
<UserCard>
orientation: "vertical"
adaptive_height: False
md_bg_color: (25/250, 25/250, 25/250, 1) if self.selected else (18/250, 18/250, 18/250, 1)
radius: 16
padding: 0, 0, 0, "16dp"
MDRelativeLayout:
MDLabel:
id: name_label
text: root.name
adaptive_size: False
color: (51/250, 54/250, 63/250, 1)
pos: "12dp", "12dp"
pos_hint: {"top": 1.25, "left": 1}
bold: True
MDLabel:
id: price_label
text: root.price
adaptive_size: True
color: (51/250, 54/250, 63/250, 1)
pos: "12dp", "12dp"
pos_hint: {"top": 0.9, "center_x": 0.9}
opacity: 0
MDLabel:
id: date_label
text: root.date
adaptive_size: True
color: (51/250, 54/250, 63/250, 1)
pos: "12dp", "12dp"
pos_hint: {"center_y": 0.1, "left": 1}
bold: False
font_size: 13
MDFillRoundFlatButton:
id: category_ellipse
size_hint: (0, 0)
text: root.category
color: (51/250, 54/250, 63/250, 1)
font_size: 15
bold: True
icon_size: 15
icon: "gift-outline"
text_color: (51/250, 54/250, 63/250, 1)
md_bg_color: (23/250, 23/250, 23/250, 1)
pos: "12dp", "12dp"
pos_hint: {"right": 0.95, "center_y": 0.2}
_no_ripple_effect: True
radius: [20]
opacity: 0
<RView@RecycleView>
viewclass: 'UserCard'
size_hint: (0.95, 0.88)
pos_hint: {'center_x': 0.5, 'y': 0.11}
bar_color: 0,0,0,0
SelectableRecycleGridLayout:
orientation: 'vertical'
spacing: "16dp"
padding: "16dp"
default_size: None, dp(100)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
我尝试更改每个视图类的 md_bg_color ,但这也没有帮助,因为它只更改了加载的视图类的颜色。我尝试通过
刷新回收视图recycle_view.refresh_from_data()
此外,视图类的颜色有时不会回到“正常”颜色,相反,这些视图类被回收,并使其他未选择的视图类看起来像被选择了。
您应该提供最少的代码,以便想要帮助您的人只需复制粘贴并运行代码(而不是写回代码并匹配您提供的代码 - 除非他们有时间/专业程序员可以解决通过阅读给出的短代码)
下面有一些其他方法可以做你想做的事,也可能不做:
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty, BooleanProperty, ListProperty
from kivy.uix.behaviors import ButtonBehavior
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.screen import MDScreen
from kivymd.utils import asynckivy
Builder.load_string('''
<Home>
app: app
RecycleView:
id: recycle_view
viewclass: 'UserCard'
bar_color: 0,0,0,0
RecycleBoxLayout:
orientation: 'vertical'
spacing: "16dp"
padding: "16dp"
default_size: None, dp(70)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
Button:
size_hint_y: .1
text: 'CLEAR'
on_press: root.clear_selected_user_card()
<UserCard>
orientation: "vertical"
size_hint: 1, None
md_bg_color: 'orange'
on_press: root.selected_node()
MDLabel:
id: name_label
text: root.name
bold: True
halign: 'center'
''')
class UserCard(ButtonBehavior, MDBoxLayout):
name = StringProperty()
selected = BooleanProperty(False)
def selected_node(self):
if self.selected:
self.selected = False
else:
self.selected = True
def on_selected(self, grid, selected):
if selected:
self.md_bg_color = 'red'
self.main_screen.update_selected_list(self, 'append')
else:
self.md_bg_color = 'orange'
self.main_screen.update_selected_list(self, 'remove')
class Home(MDScreen):
selected_data_list = ListProperty()
def update_selected_list(self, instance, task):
if task == 'append':
self.selected_data_list.append(instance)
else:
self.selected_data_list.remove(instance)
def clear_selected_user_card(self):
self.app.load_usercards_products()
class TestApp(MDApp):
def build(self):
return Home(name='home_screen')
def on_start(self):
Clock.schedule_once(self.load_usercards_products, 1)
def load_usercards_products(self, dt=None):
recycle_view = self.root.ids.recycle_view
title_list = ['title1', 'title2', 'title3', 'title4', 'title5']
async def generate_card():
recycle_view.data = []
num_inputs = 5
for i in range(num_inputs):
await asynckivy.sleep(0)
recycle_view.data.append(
{
"name": title_list[i],
"selected": False,
"main_screen": self.root
}
)
Clock.schedule_once(lambda x: asynckivy.start(generate_card()))
TestApp().run()