kivy小部件始终更新为父小部件的大小

问题描述

我使用kivy,试图创建自己的下拉菜单,以解决内置的DropDown小部件遇到的一些问题。但是,当调整窗口小部件的大小以设置打开序列的动画时,窗口小部件的大小将保持不变。经过进一步调查,我发现该小部件始终与父级RelativeLayout相同,但是我找不到原因。这是最低工作代码

from kivy.animation import Animation
from kivy.clock import Clock
from kivy.uix.relativelayout import RelativeLayout
from kivy.lang import Builder

import kivy.properties as props


KV = '''
#:import MaterialWidget materialwidget.MaterialWidget
<DropDown@RelativeLayout>
    _background: background
    canvas:
        Color:
            rgba: 1,1
        Rectangle:
            pos: root._pos
            size: root._size
    Button:
        id: background
        size: root._size
        pos: root._pos
        on_size: print("size_changed",self.size)
'''

class DropDown(RelativeLayout):
    opened = props.BooleanProperty(False)

    anchor = props.OptionProperty("tl",options=["tr","tl","br","bl"])

    _size = props.ListProperty([0,0])
    _pos = props.ListProperty([0,0])

    _background = props.ObjectProperty(None)

    def __init__(self,**kwargs):
        super(DropDown,self).__init__(**kwargs)

        #self.add_widget(self._background)

        trigger = Clock.create_trigger(lambda *args: self.on_pos())
        trig = Clock.create_trigger(lambda *args: self.on_size())

        self.bind(
            anchor=trigger,_size=trigger,opened=trig
        )

    def on_pos(self,*args):
        # calculate new pos
        invert_x = "r" in self.anchor
        invert_y = "t" in self.anchor

        self._pos = (
            self.pos[0] - self._size[0] if invert_x else 0,self.pos[1] - self._size[1] if invert_y else 0
        )

    def on_size(self,*args):
        anim = Animation(
            _size=self.size if self.opened else (0,0),duration=0.5,transition="in_out_circ"
        )
        anim.start(self)

    def open(self,*args):
        # toggle the value of open state
        self.opened = not self.opened

Builder.load_string(KV)


if __name__ == "__main__":
    from kivy.app import runTouchApp
    from kivy.uix.button import Button
    from kivy.core.window import Window

    class Test(Button):
        def __init__(self,**kwargs):
            super(Test,self).__init__(**kwargs)
            self.size = (100,100)
            self.size_hint = (None,None)

            self.dropdown = DropDown(pos=(200,100),size=(400,300))
            self.add_widget(self.dropdown)

            self.bind(on_release=lambda *args: self.dropdown.open(self))

    Window.clearcolor = (1,1,1)
    runTouchApp(test())

解决方法

您可能需要在size_hint: None,None上设置DropDown。如果size_hint不为None,它将覆盖任何size设置(包括size属性的动画)。