Python Kivy
Tutorial 59 of 65 · pythondeck.com Python course
Kivy is a Python framework for cross-platform apps including Android and iOS. Uses its own KV language for declarative UIs and OpenGL-accelerated rendering.
Kivy targets multitouch and novel UIs—games, kiosks, and Raspberry Pi dashboards—with OpenGL-accelerated widgets and KV language for declarative layout.
Python-first mobile experiments (Buildozer) start here though production mobile often shifts to native or Flutter bridges.
The framework predates Material Design—expect to craft custom themes rather than inherit platform-native chrome automatically.
Community examples and Kivy Garden extensions fill gaps for charts, maps, and complex widgets not in core.
App class — build(), lifecycle, Clock scheduling.
KV language — rules bind properties between widgets and Python classes.
Layouts — BoxLayout, GridLayout, FloatLayout; size hints and pos_hint.
Input — multitouch, gestures; collision with desktop mouse events.
Canvas — vector instructions for custom drawing.
Packaging — Buildozer for Android APK; platform-specific deps.
Kivy's strength is custom interaction design, not native OS look-and-feel. Clock.schedule_interval drives animations; default 60fps mindset. For heavy physics, pair with pymunk. Cross-compile Android requires patience with NDK versions and permissions in buildozer.spec.
Desktop Kivy works but exe size and GPU drivers vary—test target hardware early.
Sound and video providers integrate for kiosk experiences; permissions on Android still require manifest edits outside Python.
Pair Kivy with Redis or MQTT on Pi dashboards so UI thread never blocks on sensor polling loops.
Assuming widgets auto-scale like responsive web CSS without size_hint.
Blocking main loop with synchronous network in on_touch handlers.
Underestimating Android packaging debug time (SDK/NDK paths).
Mixing multiple App instances or misusing root widget rules in KV.
Hard-coding pixel sizes that break on high-DPI phones and tablets.
Keep logic in Python classes; KV only for structure and bindings.
Profile GPU draw calls when UI stutters on low-end devices.
Use Clock.create_trigger for debounced resize/layout updates.
Document hardware minimums for kiosk deployments.
Prototype touch targets at 48dp minimum for finger-friendly kiosk layouts.
Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.
The program below demonstrates hello kivy. Read the comments on each line, run the code, then change names or values to see how the output shifts.
# Example: Hello Kivy
# Run in the REPL or save as a .py file and execute with python.
from kivy.app import App
from kivy.uix.label import Label
class Demo(App):
def build(self):
return Label(text="Hello Kivy", font_size=32)
Demo().run()
This sample walks through button in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.
# Example: Button
# Run in the REPL or save as a .py file and execute with python.
from kivy.app import App
from kivy.uix.button import Button
class Demo(App):
def build(self):
btn = Button(text="Press me")
btn.bind(on_press=lambda *_: print("pressed"))
return btn
Demo().run()
Here is a hands-on illustration of kv language. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.
# Example: KV language
# Run in the REPL or save as a .py file and execute with python.
from kivy.app import App
from kivy.lang import Builder
kv = '''
BoxLayout:
orientation: 'vertical'
Label:
text: 'PythonDeck'
Button:
text: 'OK'
'''
class Demo(App):
def build(self):
return Builder.load_string(kv)
Demo().run()
The program below demonstrates label button. Read the comments on each line, run the code, then change names or values to see how the output shifts.
# Kivy uses kv language or Python for mobile-friendly UIs
from kivy.app import App # app base
from kivy.uix.boxlayout import BoxLayout # vertical/horizontal box
from kivy.uix.label import Label # text display
from kivy.uix.button import Button # tap target
class Demo(BoxLayout): # root widget
def __init__(self, **kw): # constructor
super().__init__(orientation="vertical", **kw) # vertical stack
self.lbl = Label(text="0") # counter label
self.add_widget(self.lbl) # add to layout
btn = Button(text="+") # increment button
btn.bind(on_press=self.inc) # event binding
self.add_widget(btn) # add button
def inc(self, *_): # handler ignores args
self.lbl.text = str(int(self.lbl.text) + 1) # bump counter
# Demo().run() # starts Kivy loop when executed
This sample walks through clock schedule in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.
# kivy.clock schedules callbacks on the main thread
from kivy.clock import Clock # scheduler
ticks = {"n": 0} # mutable counter
def on_tick(dt): # dt is delta time seconds
ticks["n"] += 1 # increment
print("tick", ticks["n"], "dt", round(dt, 3)) # log
if ticks["n"] >= 3: # stop after 3
return False # returning False unschedules
event = Clock.schedule_interval(on_tick, 0.2) # every 0.2s
Clock.schedule_once(lambda dt: event.cancel(), 1.0) # safety cancel
print("scheduled") # confirmation
Continue with these focused follow-up lessons on Python Kivy: