使用 Kivy ScatterLayout 进行缩放不符合预期

Scale with Kivy ScatterLayout Doesn't Behave as Expected

我想放大和缩小一组小部件。我也想滚动。我尝试使用 ScrollView 作为根小部件和 ScatterLayout 作为我想要放大和缩小的 child.The 小部件来完成此操作 children ScatterLayout。这未按预期运行。这是一个最小版本。

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.scatter import Scatter
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scrollview import ScrollView


kv = '''
#:kivy 1.11.1
<MyScatter>:
    do_translation_y: False
    do_rotation: False
    do_scale: False
    canvas:
        Color:
            hsv: .1, 1, .5
        Rectangle:
            size: 100, 100

<ScrollView>:
    size_hint: None, None
    size: 640, 480
    pos_hint: {'center_x': .5, 'center_y': .5}
    scroll_type: ['bars']
    bar_width: 10
    bar_inactive_color: self.bar_color
    canvas:
        Color:
            rgb: 1, 0, 0
        Rectangle:
            pos: self.pos
            size: self.size

<MyScatterLayout>:
    size_hint: None, None
    size: 1280, 720
    do_translation: False
    do_rotation: False
    pos_hint: {'center_x': 0.5, 'center_y': 0.5}
    canvas:
        Color:
            rgb: 0, 0, 1
        Rectangle:
            pos: self.pos
            size: self.size
'''

Builder.load_string(kv)


class MyScatter(Scatter):
    pass


class MyScatterLayout(ScatterLayout):
    pass


class MyApp(App):
    def build(self):
        layout = MyScatterLayout()
        layout.add_widget(MyScatter())
        root = ScrollView()
        root.add_widget(layout)
        return root


if __name__ == '__main__':
    MyApp().run()

缩小时,ScatterLayout 的 child 最终会超出布局边界。我希望所有 children 都保持在布局范围内,无论转换是什么。我做错了什么?

与问题相切:当我缩小到足以使 ScatterLayout 小于 ScrollView 时,滚动会将 ScatterLayout 捕捉到原点(左下角)。根据 ScrollView docs 看起来 ScrollView 的 child 应该比 ScrollView 本身大。我假设为了防止这种情况发生,我需要在滚动时增加 ScatterLayout 的大小。

不确定这是否与问题有关,但 ScatterLayoutScatter 的子类,因此其 canvas 指令必须在本地坐标中。

<MyScatterLayout>:
    ...
    canvas:
        Color:
            rgb: 0, 0, 1
        Rectangle:
            pos: 0, 0  # <- shold be this
            size: self.size

并且您不应该为 ScrollView 编写任何规则,因为它会影响可能存在于您的代码之外的所有实例。因此,改为定义一个子类并为其编写规则。

class MyScrollView(ScrollView):
    pass

<MyScrollView>:
    ...

您必须缩放 ScatterLayout 的大小以使子项的位置保持一致。我还加入了 .

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.scatter import Scatter
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scrollview import ScrollView


kv = '''
#:kivy 1.11.1
<MyScatter>:
    do_translation_y: False
    do_rotation: False
    do_scale: False
    canvas:
        Color:
            hsv: .1, 1, .5
        Rectangle:
            size: 100, 100

<MyScrollView>:
    size_hint: None, None
    size: 640, 480
    pos_hint: {'center_x': .5, 'center_y': .5}
    scroll_type: ['bars']
    bar_width: 10
    bar_inactive_color: self.bar_color
    canvas:
        Color:
            rgb: 1, 0, 0
        Rectangle:
            pos: self.pos
            size: self.size

<MyScatterLayout>:
    size_hint: None, None
    size: 1280 * self.scale, 720 * self.scale  # this is the correction
    do_translation: False
    do_rotation: False
    pos_hint: {'center_x': 0.5, 'center_y': 0.5}
    canvas:
        Color:
            rgb: 0, 0, 1
        Rectangle:
            pos: 0, 0
            size: self.size
'''

Builder.load_string(kv)


class MyScatter(Scatter):
    pass


class MyScatterLayout(ScatterLayout):
    pass


class MyScrollView(ScrollView):
    pass


class MyApp(App):
    def build(self):
        layout = MyScatterLayout()
        layout.add_widget(MyScatter())
        root = MyScrollView()
        root.add_widget(layout)
        return root


if __name__ == '__main__':
    MyApp().run()