在 RecycleView 中选择/取消选择所有 Viewclass 时遇到困难

问题描述 投票:0回答:1

我正在尝试构建一个函数来帮助用户选择/取消选择 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()

此外,视图类的颜色有时不会回到“正常”颜色,相反,这些视图类被回收,并使其他未选择的视图类看起来像被选择了。

kivy kivy-language kivymd kivy-recycleview
1个回答
0
投票

您应该提供最少的代码,以便想要帮助您的人只需复制粘贴并运行代码(而不是写回代码并匹配您提供的代码 - 除非他们有时间/专业程序员可以解决通过阅读给出的短代码)

下面有一些其他方法可以做你想做的事,也可能不做:

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()
© www.soinside.com 2019 - 2024. All rights reserved.