Table Of Contents
Relative Layout¶
New in version 1.4.0.
This layout allows you to set relative coordinates for children. If you want
absolute positioning, use the FloatLayout
.
The RelativeLayout
class behaves just like the regular
FloatLayout
except that its child widgets are positioned relative to
the layout.
When a widget with position = (0,0) is added to a RelativeLayout, the child widget will also move when the position of the RelativeLayout is changed. The child widgets coordinates remain (0,0) as they are always relative to the parent layout.
Coordinate Systems¶
Window coordinates¶
By default, there’s only one coordinate system that defines the position of widgets and touch events dispatched to them: the window coordinate system, which places (0, 0) at the bottom left corner of the window. Although there are other coordinate systems defined, e.g. local and parent coordinates, these coordinate systems are identical to the window coordinate system as long as a relative layout type widget is not in the widget’s parent stack. When widget.pos is read or a touch is received, the coordinate values are in parent coordinates. But as mentioned, these are identical to window coordinates, even in complex widget stacks as long as there’s no relative layout type widget in the widget’s parent stack.
For example:
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))
When the middle button is clicked and the touch propagates through the different parent coordinate systems, it prints the following:
>>> Box: (430.0, 282.0)
>>> Right: (430.0, 282.0)
>>> Middle: (430.0, 282.0)
As claimed, the touch has identical coordinates to the window coordinates
in every coordinate system. collide_point()
for example, takes the point in window coordinates.
Parent coordinates¶
Other RelativeLayout
type widgets are
Scatter
,
ScatterLayout
,
and ScrollView
. If such a special widget is in
the parent stack, only then does the parent and local coordinate system
diverge from the window coordinate system. For each such widget in the stack,
a coordinate system with (0, 0) of that coordinate system being at the bottom
left corner of that widget is created. Position and touch coordinates
received and read by a widget are in the coordinate system of the most
recent special widget in its parent stack (not including itself) or in window
coordinates if there are none (as in the first example). We call these
coordinates parent coordinates.
For example:
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))
Clicking on the middle button prints:
>>> Relative: (396.0, 298.0)
>>> Right: (-137.33, 298.0)
>>> Middle: (396.0, 298.0)
As the touch propagates through the widgets, for each widget, the touch is received in parent coordinates. Because both the relative and middle widgets don’t have these special widgets in their parent stack, the touch is the same as window coordinates. Only the right widget, which has a RelativeLayout in its parent stack, receives the touch in coordinates relative to that RelativeLayout which is different than window coordinates.
Local and Widget coordinates¶
When expressed in parent coordinates, the position is expressed in the coordinates of the most recent special widget in its parent stack, not including itself. When expressed in local or widget coordinates, the widgets themselves are also included.
Changing the above example to transform the parent coordinates into local coordinates:
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)))
Now, clicking on the middle button prints:
>>> Relative: (-135.33, 301.0)
>>> Right: (-135.33, 301.0)
>>> Middle: (398.0, 301.0)
This is because now the relative widget also expresses the coordinates relative to itself.
Note
Although all widgets including RelativeLayout
receive their touch
events in on_touch_xxx
in parent coordinates, these special widgets
will transform the touch position to be in local coordinates before it
calls super
. This may only be noticeable in a complex inheritance
class.
Coordinate transformations¶
Widget
provides 4 functions to transform coordinates
between the various coordinate systems. For now, we assume that the relative
keyword of these functions is False.
to_widget()
takes the coordinates expressed in
window coordinates and returns them in local (widget) coordinates.
to_window()
takes the coordinates expressed in
local coordinates and returns them in window coordinates.
to_parent()
takes the coordinates expressed in
local coordinates and returns them in parent coordinates.
to_local()
takes the coordinates expressed in
parent coordinates and returns them in local coordinates.
Each of the 4 transformation functions take a relative parameter. When the relative parameter is True, the coordinates are returned or originate in true relative coordinates - relative to a coordinate system with its (0, 0) at the bottom left corner of the widget in question.
Common Pitfalls¶
As all positions within a RelativeLayout
are relative to the position
of the layout itself, the position of the layout should never be used in
determining the position of sub-widgets or the layout’s canvas
.
Take the following kv code for example:
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
You might expect this to render a single pink rectangle; however, the content
of the RelativeLayout
is already transformed, so the use of
pos: self.pos will double that transformation. In this case, using
pos: 0, 0 or omitting pos completely will provide the expected result.
This also applies to the position of sub-widgets. Instead of positioning a
Widget
based on the layout’s own position:
RelativeLayout:
Widget:
pos: self.parent.pos
Widget:
center: self.parent.center
use the pos_hint
property:
RelativeLayout:
Widget:
pos_hint: {'x': 0, 'y': 0}
Widget:
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
Changed in version 1.7.0: Prior to version 1.7.0, the RelativeLayout
was implemented as a
FloatLayout
inside a
Scatter
. This behaviour/widget has
been renamed to ScatterLayout. The RelativeLayout
now only
supports relative positions (and can’t be rotated, scaled or translated on
a multitouch system using two or more fingers). This was done so that the
implementation could be optimized and avoid the heavier calculations of
Scatter
(e.g. inverse matrix, recalculating multiple properties
etc.)
- class kivy.uix.relativelayout.RelativeLayout(**kw)[source]¶
Bases:
kivy.uix.floatlayout.FloatLayout
RelativeLayout class, see module documentation for more information.
- do_layout(*args)[source]¶
This function is called when a layout is called by a trigger. If you are writing a new Layout subclass, don’t call this function directly but use
_trigger_layout()
instead.The function is by default called before the next frame, therefore the layout isn’t updated immediately. Anything depending on the positions of e.g. children should be scheduled for the next frame.
New in version 1.0.8.
- on_touch_down(touch)[source]¶
Receive a touch down event.
- Parameters
- touch:
MotionEvent
class Touch received. The touch is in parent coordinates. See
relativelayout
for a discussion on coordinate systems.
- touch:
- Returns
bool If True, the dispatching of the touch event will stop. If False, the event will continue to be dispatched to the rest of the widget tree.
- on_touch_move(touch)[source]¶
Receive a touch move event. The touch is in parent coordinates.
See
on_touch_down()
for more information.
- on_touch_up(touch)[source]¶
Receive a touch up event. The touch is in parent coordinates.
See
on_touch_down()
for more information.
- to_local(x, y, **k)[source]¶
Transform parent coordinates to local (current widget) coordinates.
See
relativelayout
for details on the coordinate systems.- Parameters
- relative: bool, defaults to False
Change to True if you want to translate coordinates to relative widget coordinates.
- to_parent(x, y, **k)[source]¶
Transform local (current widget) coordinates to parent coordinates.
See
relativelayout
for details on the coordinate systems.- Parameters
- relative: bool, defaults to False
Change to True if you want to translate relative positions from a widget to its parent coordinates.