Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecycleView + adaptive_size + ready list #1676

Open
AHiXilTOr opened this issue Apr 14, 2024 · 0 comments
Open

RecycleView + adaptive_size + ready list #1676

AHiXilTOr opened this issue Apr 14, 2024 · 0 comments

Comments

@AHiXilTOr
Copy link

Description of the Bug

The size of the elements does not have time to be set, and adaptive_size severely kills performance.

Code and Logs

import asynckivy

from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty, BooleanProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior

from kivymd.uix.appbar import MDActionBottomAppBarButton
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.app import MDApp

from faker import Faker

KV = """
#:import MDFabBottomAppBarButton kivymd.uix.appbar.MDFabBottomAppBarButton


<UserCard>
    orientation: "vertical"
    adaptive_height: True
    md_bg_color: "#373A22" if self.selected else "#1F1E15"
    radius: 16
    padding: 0, 0, 0, "16dp"

    MDListItem:
        theme_bg_color: "Custom"
        md_bg_color: root.md_bg_color
        radius: root.radius
        ripple_effect: False

        MDListItemLeadingAvatar:
            source: root.avatar

        MDListItemHeadlineText:
            text: root.name
            theme_text_color: "Custom"
            text_color: "#8A8D79"

        MDListItemSupportingText:
            text: root.time
            theme_text_color: "Custom"
            text_color: "#8A8D79"

    MDLabel:
        text: root.text
        adaptive_height: True
        theme_text_color: "Custom"
        text_color: "#8A8D79"
        padding_x: "16dp"

    Widget:


MDFloatLayout:
    md_bg_color: "#151511"

    RecycleView:
        id: card_list
        viewclass: "UserCard"

        SelectableRecycleGridLayout:
            orientation: 'vertical'
            spacing: "16dp"
            padding: "16dp"
            default_size: None, dp(120)
            default_size_hint: 1, None
            size_hint_y: None
            height: self.minimum_height
            multiselect: True
            touch_multiselect: True

    MDBottomAppBar:
        id: bottom_appbar
        scroll_cls: card_list
        allow_hidden: True
        theme_bg_color: "Custom"
        md_bg_color: "#232217"

        MDFabBottomAppBarButton:
            id: fab_button
            icon: "plus"
            theme_bg_color: "Custom"
            md_bg_color: "#373A22"
            theme_icon_color: "Custom"
            icon_color: "#ffffff"
"""


class UserCard(RecycleDataViewBehavior, MDBoxLayout):
    name = StringProperty()
    time = StringProperty()
    text = StringProperty()
    avatar = StringProperty()
    callback = ObjectProperty(lambda x: x)

    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        self.index = index
        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


class SelectableRecycleGridLayout(
    FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout
):
    pass


class BottomAppBarButton(MDActionBottomAppBarButton):
    theme_icon_color = "Custom"
    icon_color = "#8A8D79"


class Example(MDApp):
    selected_cards = False

    def build(self):
        return Builder.load_string(KV)

    def on_tap_card(self, *args):
        datas = [data["selected"] for data in self.root.ids.card_list.data]
        if True in datas and not self.selected_cards:
            self.root.ids.bottom_appbar.action_items = [
                BottomAppBarButton(icon="gmail"),
                BottomAppBarButton(icon="label-outline"),
                BottomAppBarButton(icon="bookmark"),
            ]
            self.root.ids.fab_button.icon = "pencil"
            self.selected_cards = True
        else:
            if len(list(set(datas))) == 1 and not list(set(datas))[0]:
                self.selected_cards = False
            if not self.selected_cards:
                self.root.ids.bottom_appbar.action_items = [
                    BottomAppBarButton(icon="magnify"),
                    BottomAppBarButton(icon="trash-can-outline"),
                    BottomAppBarButton(icon="download-box-outline"),
                ]
                self.root.ids.fab_button.icon = "plus"

    def on_start(self):
        async def generate_card():
            self.root.ids.card_list.data.extend(
                [
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                    {
                        "name": fake.name(),
                        "time": fake.date(),
                        "avatar": fake.image_url(),
                        "text": fake.text(),
                        "selected": False,
                        "callback": self.on_tap_card,
                    },
                ]
            )

        super().on_start()
        self.on_tap_card()
        fake = Faker()
        Clock.schedule_once(lambda x: asynckivy.start(generate_card()))


Example().run()

Versions

  • OS: any
  • Python: any
  • Kivy: 2.3.0
  • KivyMD: 2.0.1.dev0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant