← Volver al listado de tecnologías

KivyMD - Material Design

Por: SiempreListo
kivykivymdmaterial-designui

¿Qué es KivyMD?

Biblioteca de widgets Material Design para Kivy. Proporciona componentes modernos y estilizados.

Instalación

pip install kivymd

# Versión desarrollo
pip install https://github.com/kivymd/KivyMD/archive/master.zip

App Base

from kivymd.app import MDApp
from kivymd.uix.label import MDLabel

class MiApp(MDApp):
    def build(self):
        return MDLabel(
            text='¡Hola KivyMD!',
            halign='center'
        )

if __name__ == '__main__':
    MiApp().run()

Temas y Colores

from kivymd.app import MDApp

class MiApp(MDApp):
    def build(self):
        # Paleta de colores
        self.theme_cls.primary_palette = 'Blue'
        self.theme_cls.primary_hue = '500'
        self.theme_cls.accent_palette = 'Amber'

        # Tema claro/oscuro
        self.theme_cls.theme_style = 'Dark'  # o 'Light'

        return MiWidget()

Paletas Disponibles

Red, Pink, Purple, DeepPurple, Indigo, Blue, LightBlue, Cyan, Teal, Green, LightGreen, Lime, Yellow, Amber, Orange, DeepOrange, Brown, Gray, BlueGray

Botones

MDRaisedButton

MDRaisedButton:
    text: 'Botón Elevado'
    on_press: print('Click')

MDFlatButton

MDFlatButton:
    text: 'Botón Plano'

MDIconButton

MDIconButton:
    icon: 'heart'
    on_press: print('Like')

MDFloatingActionButton

MDFloatingActionButton:
    icon: 'plus'
    pos_hint: {'center_x': 0.9, 'center_y': 0.1}

Campos de Texto

MDTextField

MDTextField:
    hint_text: 'Usuario'
    helper_text: 'Ingresa tu nombre de usuario'
    helper_text_mode: 'on_focus'
    icon_right: 'account'
    max_text_length: 20

Modos de Helper Text

ModoComportamiento
on_focusMuestra al enfocar
persistentSiempre visible
on_errorSolo con error
MDTextField:
    hint_text: 'Email'
    helper_text: 'Email inválido'
    helper_text_mode: 'on_error'
    validator: 'email'

Cards

MDCard:
    size_hint: None, None
    size: '280dp', '180dp'
    pos_hint: {'center_x': 0.5, 'center_y': 0.5}
    elevation: 4
    padding: '8dp'
    radius: [15, 15, 15, 15]

    MDBoxLayout:
        orientation: 'vertical'

        MDLabel:
            text: 'Título'
            font_style: 'H6'

        MDLabel:
            text: 'Descripción de la tarjeta'

Listas

MDList con Items

ScrollView:
    MDList:
        OneLineListItem:
            text: 'Item simple'

        TwoLineListItem:
            text: 'Título'
            secondary_text: 'Subtítulo'

        ThreeLineListItem:
            text: 'Título'
            secondary_text: 'Segunda línea'
            tertiary_text: 'Tercera línea'

Con Iconos

MDList:
    OneLineIconListItem:
        text: 'Configuración'
        IconLeftWidget:
            icon: 'cog'

    OneLineAvatarListItem:
        text: 'Usuario'
        ImageLeftWidget:
            source: 'avatar.png'
MDNavigationLayout:
    MDScreenManager:
        MDScreen:
            MDTopAppBar:
                title: 'Mi App'
                left_action_items: [['menu', lambda x: nav_drawer.set_state('toggle')]]

    MDNavigationDrawer:
        id: nav_drawer

        MDNavigationDrawerMenu:
            MDNavigationDrawerHeader:
                title: 'Mi App'
                text: '[email protected]'

            MDNavigationDrawerItem:
                text: 'Inicio'
                icon: 'home'

            MDNavigationDrawerItem:
                text: 'Configuración'
                icon: 'cog'

Tabs

MDTabs:
    id: tabs

    Tab:
        title: 'Tab 1'
        MDLabel:
            text: 'Contenido 1'
            halign: 'center'

    Tab:
        title: 'Tab 2'
        MDLabel:
            text: 'Contenido 2'
            halign: 'center'
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.floatlayout import MDFloatLayout

class Tab(MDFloatLayout, MDTabsBase):
    pass

Diálogos

from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton

class MiApp(MDApp):
    dialog = None

    def mostrar_dialogo(self):
        if not self.dialog:
            self.dialog = MDDialog(
                title='Confirmar',
                text='¿Estás seguro?',
                buttons=[
                    MDFlatButton(
                        text='CANCELAR',
                        on_release=lambda x: self.dialog.dismiss()
                    ),
                    MDFlatButton(
                        text='ACEPTAR',
                        on_release=lambda x: self.aceptar()
                    ),
                ],
            )
        self.dialog.open()

Snackbar

from kivymd.uix.snackbar import MDSnackbar

MDSnackbar(
    MDLabel(
        text='Operación completada'
    )
).open()

Bottom Navigation

MDBottomNavigation:
    MDBottomNavigationItem:
        name: 'home'
        text: 'Inicio'
        icon: 'home'

        MDLabel:
            text: 'Pantalla Inicio'
            halign: 'center'

    MDBottomNavigationItem:
        name: 'search'
        text: 'Buscar'
        icon: 'magnify'

        MDLabel:
            text: 'Pantalla Búsqueda'
            halign: 'center'

Iconos

KivyMD usa Material Design Icons. Buscar en: https://materialdesignicons.com/

MDIconButton:
    icon: 'heart'

MDIcon:
    icon: 'account-circle'
    halign: 'center'

Ejemplo: App de Notas

from kivymd.app import MDApp
from kivymd.uix.list import OneLineListItem

class NotasApp(MDApp):
    def build(self):
        self.theme_cls.primary_palette = 'Teal'
        self.theme_cls.theme_style = 'Light'

    def agregar_nota(self, texto):
        if texto.strip():
            self.root.ids.lista.add_widget(
                OneLineListItem(text=texto)
            )
            self.root.ids.campo.text = ''
MDScreen:
    MDBoxLayout:
        orientation: 'vertical'

        MDTopAppBar:
            title: 'Mis Notas'

        MDBoxLayout:
            padding: '10dp'
            spacing: '10dp'
            size_hint_y: None
            height: '60dp'

            MDTextField:
                id: campo
                hint_text: 'Nueva nota'

            MDIconButton:
                icon: 'plus'
                on_press: app.agregar_nota(campo.text)

        ScrollView:
            MDList:
                id: lista

Recursos

RecursoURL
Documentaciónhttps://kivymd.readthedocs.io/
GitHubhttps://github.com/kivymd/KivyMD
Kitchen Sinkhttps://github.com/kivymd/KitchenSink
Iconoshttps://materialdesignicons.com/

Testing de KivyMD

# test_kivymd.py
import unittest
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.textfield import MDTextField
from kivymd.uix.card import MDCard

class TestKivyMD(unittest.TestCase):
    def test_button_creacion(self):
        btn = MDRaisedButton(text='Test')
        self.assertEqual(btn.text, 'Test')

    def test_textfield(self):
        campo = MDTextField(hint_text='Email')
        self.assertEqual(campo.hint_text, 'Email')

    def test_card(self):
        card = MDCard(elevation=4)
        self.assertEqual(card.elevation, 4)

    def test_theme_existe(self):
        # Verificar que MDApp tiene theme_cls
        self.assertTrue(hasattr(MDApp, 'theme_cls'))

if __name__ == '__main__':
    unittest.main()

Probar en Dispositivo con ADB

# Verificar tema oscuro/claro del sistema
adb shell settings get secure ui_night_mode

# Cambiar tema del sistema para probar
adb shell cmd uimode night yes  # Modo oscuro
adb shell cmd uimode night no   # Modo claro

# Ver tamaño de fuente del sistema
adb shell settings get system font_scale

# Probar con diferentes densidades
adb shell wm density 320
adb shell wm density reset

Resumen