动态添加 Widget 到 ScrollView - Kivy

Dynamically adding Widget to ScrollView - Kivy

我正在尝试将小部件添加到 kivy 滚动视图。滚动视图工作正常,但是当我尝试在滚动视图底部添加一个小部件时,滚动视图会自动调整其 scroll_y。这看起来很糟糕,因为滚动视图会跳转!在我看来,这是滚动视图的常见行为。我如何编辑或设置滚动视图,以便用户可以在滚动视图不改变位置的情况下继续滚动。 提前致谢!

是的,这是正常的 ScrollView 行为。该行为是因为 ScrollView 不调整 scroll_y 值,这在大多数情况下会导致滚动。您可以通过计算一个新的 scroll_y 值来避免这种行为,该值旨在使视口的相同部分在 ScrollView 中保持可见。如果添加的 Widget 具有已知的 height,这很容易完成。这是一个这样做的例子:

from functools import partial

from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.label import Label

kv = '''
BoxLayout:
    orientation: 'vertical'
    Button:
        text: 'add'
        on_release: app.add_new_widget()
    ScrollView:
        id: scroll
        BoxLayout:
            id: box
            orientation: 'vertical'
            size_hint_y: None
            height: self.minimum_height
'''

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

    def add_new_widget(self):
        vp_height = self.root.ids.scroll.viewport_size[1]
        sv_height = self.root.ids.scroll.height

        # add a new widget (must have preset height)
        label = Label(text='Widget #' + str(self.count), size_hint=(1, None), height=50)
        self.root.ids.box.add_widget(label)
        self.count += 1

        if vp_height > sv_height:  # otherwise there is no scrolling
            # calculate y value of bottom of scrollview in the viewport
            scroll = self.root.ids.scroll.scroll_y
            bottom = scroll * (vp_height - sv_height)

            # use Clock.schedule_once because we need updated viewport height
            # this assumes that new widgets are added at the bottom
            # so the current bottom must increase by the widget height to maintain position
            Clock.schedule_once(partial(self.adjust_scroll, bottom+label.height), -1)

    def adjust_scroll(self, bottom, dt):
        vp_height = self.root.ids.scroll.viewport_size[1]
        sv_height = self.root.ids.scroll.height
        self.root.ids.scroll.scroll_y = bottom / (vp_height - sv_height)

TestApp().run()

add_new_widget()方法每次调用都会添加另一个Label,新的Label有指定的height(本例中为50)。如有必要,将调用 adjust_scroll() 方法,并计算新的 scroll_y 以防止 ScrollView 滚动。