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 1 year 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