Coder Social home page Coder Social logo

nested-scrollview-kivy's Introduction

nested-scrollview-kivy

Learn how to implement nested scrolling in Kivy apps

nested-scrollview-kivy's People

Contributors

filipemarch avatar

Stargazers

Sk Sahil avatar Andreas Ecker avatar

Watchers

Andreas Ecker avatar  avatar

Forkers

sahil-pixel

nested-scrollview-kivy's Issues

Very slow scroll transfer from inner to outer when there is a single inner

nested_vertical_sv_bug2-2024-03-08_18.34.18.mp4
from kivy.app import App
from kivy.core.window import Window
from kivy.factory import Factory as F
from kivy.lang import Builder


class NestedScrollBehavior(F.EventDispatcher):
    children_scrolls = F.ListProperty()
    inner = F.BooleanProperty(True)

    def on_touch_down(self, touch):
        if self.inner:
            return True
        return super().on_touch_down(touch)

    def on_touch_move(self, touch):
        if self.inner:
            return True
        return super().on_touch_move(touch)

    def on_touch_up(self, touch):
        if self.inner:
            return True
        return super().on_touch_up(touch)

    def check_if_should_scroll_inner(self, *args):
        if self.inner:
            return True

        if not self.children_scrolls:
            return

        if not self.collide_point(*args[0].pos):
            return

        touch = args[0]

        uid = self._get_uid()
        if uid not in touch.ud:
            # check if any of the children scrolls are being touched
            for child_scroll in self.children_scrolls:
                x, y = child_scroll.to_window(*child_scroll.pos)
                if (
                    x < touch.pos[0] < x + child_scroll.width
                    and y < touch.pos[1] < y + child_scroll.height
                ):
                    self.scroll_inner(child_scroll, touch)
                    return
        else:
            print("uid exists")

    def scroll_inner(self, child, touch):
        dy = touch.dy
        scroll_percentage = dy / self.height

        # print(f"scroll_percentage: {scroll_percentage}")
        self.effect_x.velocity = 0
        self.effect_y.velocity = 0

        if scroll_percentage < 0 and child.scroll_y == 1:
            # This means we are scrolling up
            # print("scrolling up!")
            if self.scroll_y != 1:
                if self.scroll_y - scroll_percentage > 1:
                    self.scroll_y = 1
                else:
                    self.scroll_y -= scroll_percentage / len(self.children_scrolls)

        elif scroll_percentage > 0 and child.scroll_y == 0:
            # This means we are scrolling down
            # print("scrolling down!")
            if self.scroll_y != 0:
                if self.scroll_y - scroll_percentage < 0:
                    self.scroll_y = 0
                else:
                    self.scroll_y -= scroll_percentage / len(self.children_scrolls)


class BaseScroll(F.ScrollView, NestedScrollBehavior):
    pass


class BaseRecycle(F.RecycleView, NestedScrollBehavior):
    pass


kv = """
<ColoredLabel@Label>:
    bg_color: .5, .5, 0, 1
    size_hint_y: None
    height: self.texture_size[1]

    canvas.before:
        Color:
            rgba: self.bg_color
        Rectangle:
            size: self.size
            pos: self.pos

<BaseScroll>
    on_scroll_move: root.check_if_should_scroll_inner(args[1])
    do_scroll_y: True
    do_scroll_x: False
    effect_cls: 'ScrollEffect'
    always_overscroll: False

<BaseRecycle>
    on_scroll_move: root.check_if_should_scroll_inner(args[1])

BaseScroll:
    children_scrolls: [inner_rv.__self__]
    inner: False

    BoxLayout:
        orientation: 'vertical'
        size_hint_y: None
        height: self.minimum_height

        ColoredLabel:
            text: 'Outer Label\\n' * 15

        Button:
            size_hint_y: None
            height: dp(200)

        BaseRecycle:
            id: inner_rv
            data: [{'text': str(x)} for x in range(20)]
            viewclass: 'Label'
            size_hint_y: None
            height: dp(200)
            effect_cls: 'ScrollEffect'
            RecycleBoxLayout:
                orientation: 'vertical'
                default_size: None, dp(100)
                default_size_hint: 1, None
                padding: dp(10), 0
                spacing: dp(10)
                size_hint_y: None
                height: self.minimum_height
"""


class TestApp(App):
    def build(self):
        return Builder.load_string(kv)


TestApp().run()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.