Skip to content

Handle mobile screen geometry

Phones have notches, rounded corners, system bars, and on-screen keyboards that cover part of the window. Kivy 3.0 reports the geometry you need to lay out around them through its kivy.mobile module. This page shows how to pad your layout by the safe-area insets on Android and iOS.

kivy.mobile is part of Kivy, not kivyforge. kivyforge adds nothing to your app for it.

Before you begin

  • A configured Android or iOS app that depends on Kivy 3.0. kivy.mobile doesn't exist in Kivy 2.3.1. On Android, a Kivy 2.3.1 app (kivy_generation = 2) needs no padding: kivyforge keeps its window clear of the system bars and the notch.
  • On Android, kivy_generation = 3 in [tool.kivy.android], and pyjnius in [project].dependencies.
  • For safe-area insets on Android, a device or emulator running API level 30 or higher. Below API 30, the insets are all zero.

What kivy.mobile provides

Function Returns
get_safe_area() A dict with top, left, bottom, and right insets.
get_scale() The display scale factor.
get_dpi() The display's dots per inch.
get_density() The display density.
get_keyboard_height() The height of the on-screen keyboard, 0 when hidden.
subscribe_keyboard_height(callback) Registers a callback for keyboard height changes.

kivy.mobile works only on Android and iOS. Guard the import so the same code also runs on the desktop.

Pad your layout by the safe area

  1. Add a helper that returns the insets in Kivy pixels. get_safe_area() returns pixels on Android but points on iOS, so scale only on iOS:

    from kivy.utils import platform
    
    
    def safe_area_insets():
        """Return [left, top, right, bottom] in Kivy pixels."""
        if platform not in ("ios", "android"):
            return [0, 0, 0, 0]
        import kivy.mobile as mobile
    
        insets = mobile.get_safe_area()
        scale = mobile.get_scale() if platform == "ios" else 1.0
        return [insets[side] * scale for side in ("left", "top", "right", "bottom")]
    
  2. Apply the insets as padding on your root layout, and refresh them on the next frame and whenever the window resizes, because they change with rotation:

    from kivy.clock import Clock
    from kivy.core.window import Window
    from kivy.uix.boxlayout import BoxLayout
    
    
    class Root(BoxLayout):
        def on_kv_post(self, base_widget):
            Clock.schedule_once(self.refresh_insets, 0)
            Window.bind(on_resize=lambda *_: Clock.schedule_once(self.refresh_insets, 0))
    
        def refresh_insets(self, *_):
            self.padding = safe_area_insets()
    

Verify

Run the app on a device or emulator with a notch or gesture navigation:

kivyforge run -p android
kivyforge run -p ios --simulator

Confirm that no content sits under the status bar, the notch, or the navigation area, and that it stays clear after you rotate the device.

The android-safe-area example in the kivyforge repository paints the unsafe region red so you can see the insets. The mobile-geometry example displays every value kivy.mobile reports, including the live keyboard height.

What's next