目录
相对布局¶
在 1.4.0 版本加入.
此布局允许您为子组件设置相对坐标。若需绝对定位,请使用 FloatLayout。
:类 RelativeLayout 的行为与常规的 FloatLayout 类似,不同之处在于其子控件是相对于布局进行定位的。
当一个位置为(0,0)的控件被添加到RelativeLayout中时,当RelativeLayout的位置改变时,子控件也会随之移动。子控件的坐标始终保持为(0,0),因为它们始终相对于父布局。
坐标系¶
窗口坐标¶
默认情况下,只有一个坐标系定义了控件的位置以及分发给它们的事件坐标:窗口坐标系,其原点(0, 0)位于窗口左下角。尽管还定义了其他坐标系,例如局部坐标和父坐标,但只要控件的父级堆栈中没有相对布局类型的控件,这些坐标系就与窗口坐标系相同。当读取`widget.pos`或接收到触摸事件时,坐标值是以父坐标表示的。但如前所述,只要控件的父级堆栈中没有相对布局类型的控件,这些坐标与窗口坐标是一致的,即使在复杂的控件堆栈中也是如此。
例如:
BoxLayout:
Label:
text: 'Left'
Button:
text: 'Middle'
on_touch_down: print('Middle: {}'.format(args[1].pos))
BoxLayout:
on_touch_down: print('Box: {}'.format(args[1].pos))
Button:
text: 'Right'
on_touch_down: print('Right: {}'.format(args[1].pos))
当中间按钮被点击,且触摸事件在不同父级坐标系中传播时,会打印以下内容:
>>> Box: (430.0, 282.0)
>>> Right: (430.0, 282.0)
>>> Middle: (430.0, 282.0)
如所述,触摸事件在所有坐标系中的坐标与窗口坐标完全一致。例如,collide_point() 方法接受的是窗口坐标中的点。
父坐标¶
其他类型的 RelativeLayout 部件包括 Scatter、ScatterLayout 和 ScrollView。只有在父级堆栈中存在此类特殊部件时,父级和本地坐标系才会与窗口坐标系分离。对于堆栈中的每个此类部件,都会创建一个坐标系,其原点 (0, 0) 位于该部件的左下角。**部件接收和读取的位置及触摸坐标,是在其父级堆栈中最近的特殊部件的坐标系中(不包括自身),如果没有这样的部件,则使用窗口坐标**(如第一个示例所示)。我们将这些坐标称为父坐标。
例如:
BoxLayout:
Label:
text: 'Left'
Button:
text: 'Middle'
on_touch_down: print('Middle: {}'.format(args[1].pos))
RelativeLayout:
on_touch_down: print('Relative: {}'.format(args[1].pos))
Button:
text: 'Right'
on_touch_down: print('Right: {}'.format(args[1].pos))
点击中间按钮会打印:
>>> Relative: (396.0, 298.0)
>>> Right: (-137.33, 298.0)
>>> Middle: (396.0, 298.0)
当触摸事件在控件间传播时,每个控件接收到的触摸坐标都是相对于其父控件的。由于相对控件和中间控件的父级堆栈中没有这些特殊控件,因此它们接收到的触摸坐标与窗口坐标相同。只有右侧控件,其父级堆栈中包含一个RelativeLayout,接收到的触摸坐标是相对于该RelativeLayout的,这与窗口坐标不同。
局部坐标与控件坐标¶
当以父坐标表示时,位置是在其父堆栈中最近的特殊部件的坐标中表达的,不包括其自身。当以局部或部件坐标表示时,部件本身也包括在内。
将上述示例改为将父坐标转换为局部坐标:
BoxLayout:
Label:
text: 'Left'
Button:
text: 'Middle'
on_touch_down: print('Middle: {}'.format(self.to_local(*args[1].pos)))
RelativeLayout:
on_touch_down: print('Relative: {}'.format(self.to_local(*args[1].pos)))
Button:
text: 'Right'
on_touch_down: print('Right: {}'.format(self.to_local(*args[1].pos)))
现在,点击中间按钮会打印::
>>> Relative: (-135.33, 301.0)
>>> Right: (-135.33, 301.0)
>>> Middle: (398.0, 301.0)
这是因为现在相对部件(relative widget)也表达了相对于自身的坐标。
备注
尽管所有控件(包括 RelativeLayout)都在父坐标中通过 on_touch_xxx 接收触摸事件,但这些特殊控件会在调用 super 之前将触摸位置转换为本地坐标。这一点在复杂的继承类中可能才会明显体现出来。
坐标变换¶
Widget 提供了4个函数,用于在不同坐标系之间转换坐标。目前,我们假设这些函数的 relative 关键字为 False。to_widget() 接收以窗口坐标表示的坐标,并将其转换为本地(控件)坐标。to_window() 接收以本地坐标表示的坐标,并将其转换为窗口坐标。to_parent() 接收以本地坐标表示的坐标,并将其转换为父坐标。to_local() 接收以父坐标表示的坐标,并将其转换为本地坐标。
4个变换函数各自接受一个`relative`参数。当`relative`参数为True时,返回的坐标或坐标原点位于真正的相对坐标系中——即相对于所讨论的Widget左下角为(0, 0)的坐标系。
常见陷阱¶
由于 RelativeLayout 中的所有位置都是相对于布局自身位置的,因此在确定子部件或布局的 canvas 位置时,绝不应使用布局本身的位置。
以下面的kv代码为例:
FloatLayout:
Widget:
size_hint: None, None
size: 200, 200
pos: 200, 200
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
RelativeLayout:
size_hint: None, None
size: 200, 200
pos: 200, 200
canvas:
Color:
rgba: 1, 0, 0, 0.5
Rectangle:
pos: self.pos # incorrect
size: self.size
你可能会认为这会渲染出一个单一的粉色矩形;然而,RelativeLayout 的内容已经被变换过了,因此使用 pos: self.pos 会重复这一变换。在这种情况下,使用 pos: 0, 0 或完全省略 pos 将得到预期的结果。
这也适用于子控件的位置。与其根据布局自身的位置来定位一个 Widget:
RelativeLayout:
Widget:
pos: self.parent.pos
Widget:
center: self.parent.center
使用 pos_hint 属性:
RelativeLayout:
Widget:
pos_hint: {'x': 0, 'y': 0}
Widget:
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
在 1.7.0 版本发生变更: 在1.7.0版本之前,RelativeLayout 是通过在 Scatter 内部放置一个 FloatLayout 来实现的。这一行为/控件已被重命名为 ScatterLayout。现在,RelativeLayout 仅支持相对定位(并且不能通过使用两个或更多手指的多点触控系统进行旋转、缩放或平移)。这样做是为了优化实现,避免 Scatter 中较重的计算(例如逆矩阵、重新计算多个属性等)。
- class kivy.uix.relativelayout.RelativeLayout(**kw)[源代码]¶
基类:
FloatLayoutRelativeLayout 类,更多信息请参阅模块文档。
- do_layout(*args)[源代码]¶
当布局被触发器调用时,会调用此函数。如果你正在编写一个新的布局子类,不要直接调用此函数,而应使用
_trigger_layout()方法。该函数默认在下一帧之前调用,因此布局不会立即更新。任何依赖于子组件位置等信息的操作,都应安排在下一帧执行。
在 1.0.8 版本加入.
- on_motion(etype, me)[源代码]¶
当接收到一个运动事件时调用。
- 参数:
- etype:str
事件类型,取值为"begin"、"update"或"end"之一。
- me:
MotionEvent 收到运动事件
- 返回:
bool 类型,值为 True 时停止事件分发。
在 2.1.0 版本加入.
警告
这是一个实验性方法,只要此警告存在,它仍处于实验阶段。
- on_touch_down(touch)[源代码]¶
接收触摸按下事件。
- 参数:
- touch:
MotionEvent类 收到触摸事件。触摸坐标位于父级坐标系中。关于坐标系统的讨论,请参阅
relativelayout。
- touch:
- 返回:
bool 如果为 True,触摸事件的派发将停止。如果为 False,事件将继续派发给控件树中的其余部分。
- on_touch_move(touch)[源代码]¶
接收触摸移动事件。触摸坐标位于父级坐标系中。
更多信息请参阅
on_touch_down()。
- on_touch_up(touch)[源代码]¶
接收触摸抬起事件。触摸坐标位于父级坐标系中。
更多信息请参阅
on_touch_down()。
- to_local(x, y, **k)[源代码]¶
将父级坐标转换为本地(当前控件)坐标。
关于坐标系统的详细信息,请参阅
relativelayout。- 参数:
- relative:布尔值,默认为False
如果你想要将坐标转换为相对于控件的坐标,请将其设置为True。
- to_parent(x, y, **k)[源代码]¶
将局部(当前控件)坐标转换为父控件坐标。
关于坐标系统的详细信息,请参阅
relativelayout。- 参数:
- relative:布尔值,默认为False
如果你想要将控件的相对位置转换为其父坐标,请将其设置为True。