I am trying to build a function that helps the user select/unselect all viewclass-instances in a RecycleView.
The Problem is that while i can change the "selected" attribute of every viewclass in the RecycleView to True or False.
like this for example:
for viewclass in recycle_view.data:
viewclass['selected'] = False
-the "selected" color of the viewclasses do not update themselves, meaning it retains the "selected" color, eventhough it's technically unselected. I wonder how i can refresh the recycleview in a way, that it also the takes the color of the viewclasses into account.
This is the code that handles the creation of the vieclasses "UserCard", with all it's selecting methods:
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()))
These are the UserCard- and recycle_view classes.
<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
I have tried changing the md_bg_color of each viewclass, but that didn't help either, because it only changed the color of the viewclasses that were loaded. I've tried refreshing the recycleview via
recycle_view.refresh_from_data()
Also the color of the viewclasses did not go back to the "normal" color sometimes, instead those viewclasses were recycled and made other viewclasses, that were't selected, look like they were selected.