Search code examples
pythonkivykivy-language

Setting dynamic position of a widget by layout in Kivy


The thing I would like to receive seems to be very simple; I would like to change the size and position of my Label and TextInput widget, being dynamically resizable simultaneously. As these parameters are controlled by layouts, I was playing with linking my TextInput to the FloatLayout and my Label to AnchorLayout but it didn't help much. What am I doing wrong ?

Desirable outcome:

  • text from a Label is centralised on the bottom of that layer
  • TextInput comprises 20% of the layer it currently fills in terms of height and 80% in terms of width

What am I getting: TextInput completely disappears after linking FloatLayout to it, text in a label is not changing position at all

import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.core.window import Window
from kivy.utils import get_color_from_hex


class SearchPerformer(GridLayout):
    pass


class MyApp(App):
    def build(self):
        return SearchPerformer()


if __name__ == '__main__':
    Window.clearcolor = get_color_from_hex('#F9E29C')

MyApp().run()

and my KV file where I've defined UI:

<SearchPerformer>
GridLayout:
    size: root.size
    cols: 2
    rows: 2

    BoxLayout:
        orientation: 'vertical'
        rows: 2
        cols: 1
        AnchorLayout:
            Label:
                text: "MAKE"
                font_size: 60
                anchor_x: "center"
                anchor_y: "bottom" # Although specifying bottom, my text label doesn't move to the bottom of the layer

        FloatLayout: # When FloatLayout is added, TextInput automatically disappears
            TextInput:
                border: (50, 50, 50, 50)
                multiline: False
                font_size: 30
                size_hint: .8, .2 # So then 80% width and 50% in height of this layer does not work as well...



    BoxLayout:
        orientation: 'vertical'
        rows: 2
        cols: 1
        Label:
            text: "MODEL"
            font_size: 60
        TextInput:
            border: (50, 50, 50, 50)
            multiline: False
            font_size: 30

    BoxLayout:
        orientation: 'vertical'
        rows: 2
        cols: 1
        Label:
            text: "YEAR"
            font_size: 60
        TextInput:
            border: (50, 50, 50, 50)
            multiline: False
            font_size: 30

    BoxLayout:
        orientation: 'vertical'
        rows: 2
        cols: 1
        Label:
            text: "ENGINE"
            font_size: 60
        TextInput:
            border: (50, 50, 50, 50)
            multiline: False
            font_size: 30

Solution

  • When using the AnchorLayout, the anchor_x and anchor_y properties are part of the AnchorLayout, not its child. So that part of your kv should be:

        AnchorLayout:
            anchor_x: "center"
            anchor_y: "bottom"
            Label:
                text: "MAKE"
                font_size: 60
    

    And when you use FloatLayout, you must position its children either with pos_hint or pos. But note that pos_hint positions children relative to the position of the FloatLayout. So using:

    pos_hint: {'x':0, 'y':0}
    

    positions the child in the lower left corner of the FloatLayout, but:

    pos: (0, 0)
    

    which is the default, positions the child at the lower left corner of the display (perhaps not even inside the FloatLayout). So to get the TextInput where you want it, you can use the above pos_hint.

    Another possibility is to use RelativeLayout, where the pos coordinates are relative to the position of the RelativeLayout. In that case the default pos of (0,0) will position the child TextInput where you want it.

    You can adjust the position of the text within a Label using halign and valign, but only if the text_size is larger than required for the actual text (the texture_size). So, for example, here is a way to adjust the position of the text in one of your Labels:

        Label:
            text: "ENGINE"
            font_size: 60
            text_size: self.size  # sets text size to allow below alignments to work
            valign: 'bottom'
            halign: 'center'