Let ModalView fit all its contents widgets (kivy)

949 views Asked by At

What's the proper way to add a set of widgets into a ModalView in kivy so that the modal window fits all of its contents dynamically (without setting the height to a hard-coded pixel size)?

I have the following example script:

#!/usr/bin/env python3

import kivy
from kivy.uix.modalview import ModalView
from kivy.lang import Builder
from kivy.app import App

KV = """
BoxLayout:
    ModalView:
        size_hint: 0.9, None

        BoxLayout:
            orientation: 'vertical'

            Label:
                text: 'Dialog Title'
                font_size: 30

            Label:
                text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            Label:
                text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            Label:
                text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            Label:
                text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."

            StackLayout:
                orientation: 'rl-tb'

                Button:
                    text: "OK"
                    size_hint: None, None
                    size: self.texture_size
                    padding: '8dp', '8dp'

                Button:
                    text: "Cancel"
                    size_hint: None, None
                    size: self.texture_size
                    padding: '8dp', '8dp'
"""

class MyApp(App):
    def build(self):
        return Builder.load_string( KV )


MyApp().run()

As the kivy langauge describes, I want a modal to appear with 90% width of the app and the height should dynamically adjust to fit all the contents of the modal.

The modal's contents should be a "title" label with a set of "body" labels below it. Below these labels should be two buttons that appear on the same line. Pretty straight-forward.

But this is what I get:

widgets not appearing properly in kivy modal view

Note that the above image shows:

  1. the buttons are mostly outside the modal
  2. The title label is partially ontop of the below labels (this is not how BoxLayout should work)
  3. The title label is also partially outside the modal

How can I fix this script so that the contents of the modal appears as expected?

2

There are 2 answers

1
John Anderson On

If you use size_hint: 0.9, None, then you must specify the height of the ModalView. The simplest way to do that is to let the widgets do the calculations by using minimum_height of the children Layouts. Something like this:

<MyModal@ModalView>:
    size_hint: 0.9, None
    height: box.height
    BoxLayout:
        id: box
        orientation: 'vertical'
        size_hint: 1, None
        height: self.minimum_height
        padding: 5
        spacing: 5

        Label:
            text: 'Dialog Title'
            font_size: 30
            pos_hint: {'center_x': 0.5}
            size_hint: None, None
            size: self.texture_size

        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            pos_hint: {'center_x': 0.5}
            size_hint: None, None
            size: self.texture_size
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            pos_hint: {'center_x': 0.5}
            size_hint: None, None
            size: self.texture_size
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            pos_hint: {'center_x': 0.5}
            size_hint: None, None
            size: self.texture_size
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            pos_hint: {'center_x': 0.5}
            size_hint: None, None
            size: self.texture_size

        StackLayout:
            orientation: 'rl-tb'
            size_hint: 1, None
            height: self.minimum_height

            Button:
                text: "OK"
                size_hint: None, None
                size: self.texture_size
                padding: '8dp', '8dp'

            Button:
                text: "Cancel"
                size_hint: None, None
                size: self.texture_size
                padding: '8dp', '8dp'

Note that using minimum_height requires that the children of that Layout must have well defined heights.

2
John Anderson On

You can put a rule in your kv that describe how the ModalView should be built without making it a child of any widget. See the documentation. You could use a rule something like:

<MyModal@ModalView>:

    BoxLayout:
        orientation: 'vertical'

        Label:
            text: 'Dialog Title'
            font_size: 30

        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
        Label:
            text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."

        StackLayout:
            orientation: 'rl-tb'

            Button:
                text: "OK"
                size_hint: None, None
                size: self.texture_size
                padding: '8dp', '8dp'

            Button:
                text: "Cancel"
                size_hint: None, None
                size: self.texture_size
                padding: '8dp', '8dp'

Then in your python code, you create the ModalView like this:

from kivy.factory import Factory
modal_inst = Factory.MyModal()
modal_inst.open()