community icon indicating copy to clipboard operation
community copied to clipboard

ScrollView not triggering overscroll effects when content is the same size as scroller

Open snuq opened this issue 11 months ago • 0 comments

Software Versions

  • Python: 3.10.9
  • OS: Windows 10
  • Kivy: 2.2.1
  • Kivy installation method: PIP

Describe the bug When a ScrollView's content is the same height as itself, overscroll effects are never triggered, even if always_overscroll is set to True. This blocks some functionality like a nested ScrollView not triggering its parent's scrolling (as normally happens when overscroll is enabled).

Expected behavior The content should utilize the effect_cls to position itself to some degree, just as it does when content height does not match scrollview height

To Reproduce This example illustrates the issue: dragging the button up/down does not scroll the outer scrollview, but if the height of the button is set to self.parent.height+1, it will.

from kivy.app import App
from kivy.lang.builder import Builder
KV = """
ScrollView:
    do_scroll_y: True
    BoxLayout:
        orientation: 'vertical'
        size_hint_y: None
        height: 1000
        Widget:
        ScrollView:
            Button:
                text: 'Inner scrollview content'
                size_hint_y: None
                height: self.parent.height
        Widget:
"""

class Test(App):
    def build(self):
        return Builder.load_string(KV)

Test().run()

Proposed Solution the '_update_effect_y()' and '_update_effect_x()' functions of ScrollView should be updated to better handle this edge case, for instance, a simple addition like setting sh to a small number instead of 0 like:

    def _update_effect_y(self, *args):
        vp = self._viewport
        if not vp or not self.effect_y:
            return
        if self.effect_y.is_manual:
            sh = vp.height - self._effect_y_start_height
        else:
            sh = vp.height - self.height

        if sh < 1 and not (self.always_overscroll and self.do_scroll_y):
            return
        if sh != 0:
            sy = self.effect_y.scroll / sh
            self.scroll_y = -sy
        else:
            self.scroll_y = 1 - self.effect_y.scroll
        self._trigger_update_from_scroll()

resolves the issue and allows for overscroll effects

edit: changed the proposed solution to not cause a bug where scrolling position was set to the bottom sometimes

snuq avatar Mar 12 '24 00:03 snuq