← Volver al listado de tecnologías
ScreenManager y Navegación
ScreenManager
Gestiona múltiples pantallas con transiciones.
Estructura Básica
from kivy.uix.screenmanager import ScreenManager, Screen
class PantallaInicio(Screen):
pass
class PantallaConfig(Screen):
pass
class MiApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(PantallaInicio(name='inicio'))
sm.add_widget(PantallaConfig(name='config'))
return sm
Definir en KV
ScreenManager:
PantallaInicio:
PantallaConfig:
<PantallaInicio>:
name: 'inicio'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Pantalla de Inicio'
Button:
text: 'Ir a Configuración'
on_press: root.manager.current = 'config'
<PantallaConfig>:
name: 'config'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Configuración'
Button:
text: 'Volver'
on_press: root.manager.current = 'inicio'
Navegación
Cambiar Pantalla
# Por nombre
screen_manager.current = 'nombre_pantalla'
# Desde un Screen
self.manager.current = 'otra_pantalla'
Dirección de Transición
# Dirección: 'left', 'right', 'up', 'down'
screen_manager.transition.direction = 'left'
screen_manager.current = 'siguiente'
Button:
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'siguiente'
Tipos de Transición
| Transición | Descripción |
|---|---|
SlideTransition | Deslizar (default) |
FadeTransition | Desvanecimiento |
SwapTransition | Intercambio con zoom |
WipeTransition | Barrido |
CardTransition | Efecto carta |
NoTransition | Sin animación |
FallOutTransition | Caída |
RiseInTransition | Elevación |
from kivy.uix.screenmanager import (
ScreenManager, FadeTransition, SlideTransition
)
sm = ScreenManager(transition=FadeTransition())
# o cambiar después
sm.transition = SlideTransition(direction='up')
ScreenManager:
transition: FadeTransition()
Personalizar Transiciones
from kivy.uix.screenmanager import SlideTransition
# Duración
sm.transition.duration = 0.5
# Dirección
sm.transition.direction = 'up'
Acceder a Pantallas
# Obtener pantalla por nombre
pantalla = sm.get_screen('inicio')
# Lista de nombres
nombres = sm.screen_names
# Pantalla actual
actual = sm.current_screen
nombre_actual = sm.current
# Verificar si existe
if sm.has_screen('config'):
pass
Eventos de Screen
class MiPantalla(Screen):
def on_pre_enter(self):
"""Antes de entrar (transición iniciando)"""
print('Preparando entrada')
def on_enter(self):
"""Después de entrar (transición completada)"""
print('Pantalla visible')
def on_pre_leave(self):
"""Antes de salir"""
print('Preparando salida')
def on_leave(self):
"""Después de salir"""
print('Pantalla oculta')
Pasar Datos Entre Pantallas
Método 1: Propiedades en Screen
class DetalleScreen(Screen):
item_id = NumericProperty(0)
item_nombre = StringProperty('')
# Al navegar
detalle = sm.get_screen('detalle')
detalle.item_id = 42
detalle.item_nombre = 'Producto X'
sm.current = 'detalle'
Método 2: Via App
class MiApp(App):
datos_compartidos = DictProperty({})
# Desde cualquier pantalla
App.get_running_app().datos_compartidos['clave'] = 'valor'
Método 3: Manager personalizado
class MiManager(ScreenManager):
usuario_actual = ObjectProperty(None)
# Acceder desde Screen
self.manager.usuario_actual = usuario
Ejemplo: App con Navegación
# main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
class LoginScreen(Screen):
pass
class HomeScreen(Screen):
usuario = StringProperty('')
class PerfilScreen(Screen):
pass
class AppManager(ScreenManager):
pass
class MiApp(App):
def build(self):
return AppManager()
# mi.kv
<AppManager>:
LoginScreen:
HomeScreen:
PerfilScreen:
<LoginScreen>:
name: 'login'
BoxLayout:
orientation: 'vertical'
padding: 50
spacing: 20
Label:
text: 'Iniciar Sesión'
font_size: '24sp'
TextInput:
id: txt_usuario
hint_text: 'Usuario'
multiline: False
TextInput:
id: txt_password
hint_text: 'Contraseña'
password: True
multiline: False
Button:
text: 'Entrar'
on_press:
app.root.get_screen('home').usuario = txt_usuario.text
root.manager.current = 'home'
<HomeScreen>:
name: 'home'
BoxLayout:
orientation: 'vertical'
padding: 20
Label:
text: 'Bienvenido, ' + root.usuario
font_size: '20sp'
Button:
text: 'Ver Perfil'
on_press: root.manager.current = 'perfil'
Button:
text: 'Cerrar Sesión'
on_press: root.manager.current = 'login'
<PerfilScreen>:
name: 'perfil'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Mi Perfil'
Button:
text: 'Volver'
on_press: root.manager.current = 'home'
Navegación con Historial
class NavManager(ScreenManager):
historial = ListProperty([])
def ir_a(self, nombre):
if self.current != nombre:
self.historial.append(self.current)
self.transition.direction = 'left'
self.current = nombre
def volver(self):
if self.historial:
pantalla_anterior = self.historial.pop()
self.transition.direction = 'right'
self.current = pantalla_anterior
<MiScreen>:
Button:
text: 'Atrás'
on_press: root.manager.volver()
Cargar Pantallas Dinámicamente
class MiApp(App):
def build(self):
self.sm = ScreenManager()
self.sm.add_widget(MenuScreen(name='menu'))
return self.sm
def cargar_pantalla(self, nombre):
if not self.sm.has_screen(nombre):
if nombre == 'config':
self.sm.add_widget(ConfigScreen(name='config'))
elif nombre == 'perfil':
self.sm.add_widget(PerfilScreen(name='perfil'))
self.sm.current = nombre
Testing de Navegación
# test_screenmanager.py
import unittest
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class TestScreenManager(unittest.TestCase):
def test_agregar_screen(self):
sm = ScreenManager()
screen = Screen(name='home')
sm.add_widget(screen)
self.assertTrue(sm.has_screen('home'))
def test_cambiar_screen(self):
sm = ScreenManager()
sm.add_widget(Screen(name='a'))
sm.add_widget(Screen(name='b'))
sm.current = 'b'
self.assertEqual(sm.current, 'b')
def test_transicion(self):
sm = ScreenManager(transition=SlideTransition())
self.assertIsInstance(sm.transition, SlideTransition)
def test_screen_names(self):
sm = ScreenManager()
sm.add_widget(Screen(name='uno'))
sm.add_widget(Screen(name='dos'))
self.assertIn('uno', sm.screen_names)
self.assertIn('dos', sm.screen_names)
if __name__ == '__main__':
unittest.main()
Probar en Dispositivo con ADB
# Simular botón "atrás" de Android
adb shell input keyevent KEYCODE_BACK
# Navegar a home y volver a la app
adb shell input keyevent KEYCODE_HOME
adb shell am start -n com.ejemplo.miapp/org.kivy.android.PythonActivity
# Ver actividades en el stack
adb shell dumpsys activity activities | grep miapp
# Ver transiciones en logs
adb logcat | grep -i "screen\|transition"
Resumen
ScreenManagercontiene múltiplesScreensm.current = 'nombre'cambia pantallatransitiondefine la animaciónon_enter/on_leavemanejan eventos de navegación- Usar propiedades o App para compartir datos entre pantallas