← Volver al listado de tecnologías
Primera Aplicación
La Clase App
Toda aplicación Kivy hereda de kivy.app.App. El método build() retorna el widget raíz.
Hello World
# main.py
from kivy.app import App
from kivy.uix.label import Label
class MiApp(App):
def build(self):
return Label(text='¡Hola Kivy!')
if __name__ == '__main__':
MiApp().run()
Ciclo de Vida de la Aplicación
┌──────────────┐
│ __init__ │ Inicialización
└──────┬───────┘
▼
┌──────────────┐
│ build │ Construir UI (retorna widget raíz)
└──────┬───────┘
▼
┌──────────────┐
│ on_start │ App lista, antes de mostrar
└──────┬───────┘
▼
┌──────────────┐
│ run() │ Loop principal
└──────┬───────┘
▼
┌──────────────┐
│ on_pause │ (Móvil) App en segundo plano
└──────┬───────┘
▼
┌──────────────┐
│ on_resume │ (Móvil) App regresa a primer plano
└──────┬───────┘
▼
┌──────────────┐
│ on_stop │ App terminando
└──────────────┘
Métodos del Ciclo de Vida
from kivy.app import App
from kivy.uix.label import Label
class CicloApp(App):
def build(self):
print("build: Construyendo UI")
return Label(text='Ciclo de Vida')
def on_start(self):
print("on_start: App iniciada")
def on_pause(self):
print("on_pause: App pausada")
return True # Permite pausar
def on_resume(self):
print("on_resume: App resumida")
def on_stop(self):
print("on_stop: App terminando")
if __name__ == '__main__':
CicloApp().run()
Widgets Básicos
Label (Texto)
from kivy.uix.label import Label
label = Label(
text='Texto de ejemplo',
font_size='24sp',
color=(1, 0, 0, 1), # RGBA: Rojo
halign='center',
valign='middle'
)
Button (Botón)
from kivy.uix.button import Button
def on_press(instance):
print(f'Botón presionado: {instance.text}')
boton = Button(
text='Presióname',
font_size='20sp',
on_press=on_press
)
TextInput (Campo de texto)
from kivy.uix.textinput import TextInput
entrada = TextInput(
text='',
hint_text='Escribe aquí...',
multiline=False
)
Aplicación con Interacción
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class SaludoApp(App):
def build(self):
# Layout vertical
self.layout = BoxLayout(orientation='vertical', padding=20, spacing=10)
# Widgets
self.entrada = TextInput(
hint_text='Tu nombre',
multiline=False,
size_hint_y=None,
height=50
)
self.boton = Button(
text='Saludar',
size_hint_y=None,
height=50
)
self.boton.bind(on_press=self.saludar)
self.label = Label(text='', font_size='24sp')
# Agregar al layout
self.layout.add_widget(self.entrada)
self.layout.add_widget(self.boton)
self.layout.add_widget(self.label)
return self.layout
def saludar(self, instance):
nombre = self.entrada.text or 'Mundo'
self.label.text = f'¡Hola, {nombre}!'
if __name__ == '__main__':
SaludoApp().run()
Propiedades de Ventana
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.label import Label
# Configurar antes de crear widgets
Window.size = (400, 600)
Window.clearcolor = (0.1, 0.1, 0.1, 1) # Fondo oscuro
class VentanaApp(App):
def build(self):
return Label(text='Ventana personalizada')
if __name__ == '__main__':
VentanaApp().run()
Propiedades de Window
| Propiedad | Descripción |
|---|---|
size | Tamaño (ancho, alto) |
clearcolor | Color de fondo RGBA |
fullscreen | Modo pantalla completa |
borderless | Sin bordes |
top, left | Posición de ventana |
Manejo de Eventos de Ventana
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.label import Label
class EventosApp(App):
def build(self):
Window.bind(on_key_down=self.on_tecla)
Window.bind(on_resize=self.on_resize)
self.label = Label(text='Presiona teclas o redimensiona')
return self.label
def on_tecla(self, window, key, scancode, codepoint, modifier):
self.label.text = f'Tecla: {key}'
if key == 27: # ESC
return True # Previene cerrar
return False
def on_resize(self, window, width, height):
self.label.text = f'Tamaño: {width}x{height}'
if __name__ == '__main__':
EventosApp().run()
Convención de Nombres
El archivo .kv se asocia automáticamente por nombre:
| Clase App | Archivo KV |
|---|---|
MiApp | mi.kv |
SaludoApp | saludo.kv |
TestApp | test.kv |
La regla: nombre de clase sin “App” en minúsculas.
Testing del Ciclo de Vida
# test_app.py
import unittest
from kivy.app import App
from kivy.uix.label import Label
class MiApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.eventos = []
def build(self):
self.eventos.append('build')
return Label(text='Test')
def on_start(self):
self.eventos.append('on_start')
self.stop() # Detener para test
class TestCicloVida(unittest.TestCase):
def test_ciclo_vida_app(self):
app = MiApp()
app.run()
self.assertIn('build', app.eventos)
self.assertIn('on_start', app.eventos)
def test_label_texto(self):
label = Label(text='Hola')
self.assertEqual(label.text, 'Hola')
if __name__ == '__main__':
unittest.main()
Probar en Dispositivo con ADB
# Compilar e instalar
buildozer android debug deploy
# Ver logs específicos de tu app
adb logcat -s python:V
# Monitorear uso de memoria
adb shell dumpsys meminfo com.ejemplo.miapp
# Verificar que la app inició correctamente
adb shell ps | grep miapp
Resumen
App.build()retorna el widget raíz- El ciclo de vida incluye: build → on_start → run → on_stop
bind()conecta eventos con funciones- La ventana se configura con
kivy.core.window.Window - Archivos
.kvse asocian automáticamente por nombre