Kivy, ScrollView 在内容改变大小时自动滚动

时间:2021-05-14 00:46:42

标签: python kivy

我在 ScrollView 中有一个 GridLayout。 GridLayout 包含大约 25 个图像。图像是在运行时选择的,因此无法事先确定它们的大小。这些图片是在不同时间异步加载的(它们之间至少有 500 毫秒的差异)。

图片加载后GridLayout的大小发生变化时出现问题。据我了解,ScrollView 的 scroll_y 设置为相对于 GridLayout 的原始高度的某个值。然后,一旦图像加载完毕,GridLayout 的大小就会发生变化,但 scroll_y 仍然相对于旧高度。这会导致 ScrollView 大量向下滚动。

我已尝试通过手动更改 scroll_y 以匹配新高度来纠正此问题。我正在使用以下等式:

Equation for Finding New Scroll_Y

我从 1 中减去 scroll_y 因为滚动值 1 在 kivy 中处于最顶端。我已将此等式重新排序为以下内容并已在代码中实现:

Simplified Equation for Finding New Scroll_Y

这减少了问题,并且不那么明显的抖动,但每次加载图像时它仍会向上滚动 5-10 个像素。

这是因为我正在计算方程的新高度,基于:

  • ScrollView 的旧视口高度
  • 图像小部件的旧高度
  • 图像的新高度。

但是,这个计算出的高度比实际高度稍大,导致我调整后的 scroll_y 略微偏离。我不知道为什么实际高度要小。

我不知道从哪里开始。

这是一个指向存储库的链接,其中包含最小的可重现示例。 Grid Stuttering Example

1 个答案:

答案 0 :(得分:0)

我相信做你想做的最简单的方法是扩展ScrollView。这是一个扩展 ScrollView 的类,可以执行您想要的操作:

class ScrollViewNoStutter(ScrollView):
    child_height = NumericProperty(0)

    def add_widget(self, widget, index=0):
        super(ScrollViewNoStutter, self).add_widget(widget, index=index)
        widget.bind(size=self.child_size_changed)

    def remove_widget(self, widget):
        super(ScrollViewNoStutter, self).remove_widget(widget)
        widget.unbind(size=self.child_size_changed)

    def child_size_changed(self, child, new_child_size):
        if new_child_size[1] > self.size[1]:
            # re-calculate scroll_y

            # calculate distance between scrollview top and child top (in pixels)
            y_dist = (1.0 - self.scroll_y) * (self.child_height - self.height)

            # calculate new scroll_y that reproduces the above distance
            self.scroll_y = 1.0 - y_dist / (new_child_size[1] - self.height)

        self.child_height = new_child_size[1]

只需使用此类代替 ScrollView,您就不需要在 App 中进行任何这些计算。