Aprenda sobre variáveis, loops e funções e crie seu primeiro projeto Python em apenas 2 horas!
Você criou sua lista de lembretes com Kivy e agora quer ir além? Perfeito! Chegou o momento de transformar aquele app funcional em algo verdadeiramente profissional utilizando Python e KivyMD, que é derivado do Kivy.
Atualmente, seu código Kivy provavelmente mistura lógica de programação com definições de interface. Além disso, a aparência ainda lembra os primeiros apps dos anos 2000. Isso é completamente normal no começo.
No entanto, quando você decide evoluir o app, duas coisas ficam evidentes: primeiro, o código se torna cada vez mais difícil de manter. Segundo, a interface simplesmente não impressiona ninguém.

A solução envolve duas ferramentas poderosas: Kivy Language Python para organizar seu código e KivyMD para criar interfaces modernas. Consequentemente, você terá o mesmo app, porém com código profissional e visual impactante.
Neste artigo, você descobrirá como migrar sua lista de lembretes para essa nova arquitetura. Portanto, prepare-se para dar um salto de qualidade significativo.
O problema da organização: quando Python não basta
Todo desenvolvedor Kivy passa por essa fase. Primeiramente, você cria um app simples que funciona. Em seguida, adiciona mais funcionalidades. Posteriormente, o código começa a ficar bagunçado.
Sintomas de código desorganizado
Reconhece algum desses sinais na sua aplicação Kivy?
- Arquivos Python com mais de 200 linhas misturando interface e lógica;
- Dificuldade para encontrar onde definiu as cores de um botão específico;
- Medo de mexer no código porque “se funciona, não mexe”;
- Demora excessiva para implementar mudanças simples na interface.
Esses são sinais clássicos de que chegou a hora de organizar melhor sua aplicação.
O dilema do desenvolvedor Kivy
Por um lado, Python funciona perfeitamente para apps simples. Por outro lado, conforme a complexidade aumenta, surgem problemas reais de manutenibilidade.
Considere este exemplo real de como o código cresce naturalmente:
# Versão inicial - 50 linhas
class MeuApp(App):
def build(self):
return Button(text="Clique")
# Após algumas funcionalidades - 200+ linhas
class MeuApp(App):
def build(self):
layout = BoxLayout(orientation="vertical")
# ... 150 linhas de definições de interface
# ... misturado com lógica de negócioEvidentemente, essa abordagem não escala bem.
Por que separar interface e lógica no Kivy/Python
A separação entre interface e lógica traz benefícios fundamentais:
✅ Vantagens da organização
- Código Python e Kivy mais limpo visualmente;
- Interface definida de forma declarativa;
- Facilidade para fazer alterações visuais;
- Colaboração mais eficiente em equipes.
⚠️ Sem organização
- Código gigante e confuso;
- Alterações do Kivy requerem muita lógica;
- Dificuldade para debugar problemas;
- Manutenção cada vez mais complexa.
Felizmente, existe uma solução elegante: Kivy Language Python. Esta ferramenta permite separar completamente a definição da interface da lógica do aplicativo.
Kivy Language: separando o que é o quê
O Kivy Language Python funciona como HTML para web, mas específico para Kivy. Basicamente, você define toda a interface em arquivos .kv, enquanto mantém apenas a lógica nos arquivos .py.
Sintaxe básica em 5 minutos
A sintaxe do Kivy é surpreendentemente simples. Veja esta comparação prática:
Vamos migrar um pedaço da nossa lista de lembretes para Kivy. Primeiramente, observe como era no Python:
def build(self):
layout = BoxLayout(orientation="vertical")
titulo = Label(text="Meus Lembretes", font_size="24sp")
layout.add_widget(titulo)
return layoutAgora, veja como fica usando Kivy Language Python:
arquivo: main.py
class ListaLembretesApp(App):
def build(self):
return Builder.load_file("interface.kv")arquivo: interface.kv
BoxLayout:
orientation: "vertical"
Label:
text: "Meus Lembretes"
font_size: "24sp"
size_hint_y: 0.1Como você pode ver, a sintaxe Kivy é mais limpa e declarativa. Além disso, elimina a necessidade de criar variáveis para cada widget. Percebe a diferença? O arquivo Python agora tem apenas 3 linhas! Consequentemente, toda a complexidade visual foi movida para o arquivo Kivy.
Organizando arquivos Kivy
Para projetos maiores, recomendo essa estrutura de organização:
meu_app/
├── main.py # Lógica principal
├── interfaces/
│ ├── main.kv # Interface principal
│ ├── lembretes.kv # Tela de lembretes
│ └── configuracoes.kv # Tela de configurações
└── models/
└── lembrete.py # Classes de dadosEsta organização permite que você mantenha cada tela em seu próprio arquivo. Portanto, fica muito mais fácil encontrar e modificar elementos específicos.
Depurando problemas comuns
Durante a migração para Kivy Language Python, você provavelmente encontrará alguns erros típicos:
Problema 1: Arquivo Kivy não encontrado
FileNotFoundError: [Errno 2] No such file or directory: 'interface.kv'Solução: verifique se o arquivo .kv está na pasta correta e se está sendo carregado pelo Builder dentro de algum código Python.
Problema 2: Propriedades não reconhecidas
AttributeError: 'Button' object has no attribute 'texto'Solução: propriedades KV devem estar de acordo com a documentação, e nesse caso, o correto seria text em inglês.
Visual moderno com KivyMD: apps que impressionam
Agora que você organizou o código, chegou a hora de elevar o nível visual. Apps Kivy padrão funcionam, mas definitivamente não impressionam visualmente.
O problema visual do Kivy padrão
Por padrão, Kivy usa elementos visuais que remetem aos anos 2000. Embora funcionais, esses elementos passam uma impressão amadora. Consequentemente, isso pode prejudicar a percepção do seu trabalho.
Compare estes elementos visuais:
Kivy Padrão
- Botões com bordas duras
- Cores básicas (cinza, azul simples)
- Sem transições ou animações
- Visual “quadrado” e rígido
KivyMD Profissional
- Material Design nativo
- Paleta de cores harmoniosa
- Animações fluidas incluídas
- Visual moderno e polido
A solução: Material Design com KivyMD
KivyMD implementa completamente o Material Design do Google. Como resultado, você obtém componentes visuais profissionais sem esforço adicional.
Primeiramente, instale o KivyMD:
pip install kivymdEm seguida, faça a migração básica da sua aplicação:
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
class MeuApp(MDApp):
def build(self):
return MDLabel(text="Hello World!", halign="center")
MeuApp().run()Instantaneamente, você terá uma aplicação com visual Material Design. Além disso, todos os componentes seguirão automaticamente as diretrizes de design do Google.
Componentes essenciais do KivyMD
Estes são os componentes que farão a maior diferença visual na sua aplicação:
MDCard – Para agrupar conteúdo:
MDCard:
elevation: 3
shadow_softness: 12
md_bg_color: app.theme_cls.surface_colorMDRaisedButton – Botões com Material Design:
MDRaisedButton:
text: "Clique aqui"
theme_icon_color: "Custom"
md_bg_color: app.theme_cls.primary_colorMDTextField – Campos de entrada modernos:
MDTextField:
hint_text: "Digite seu lembrete"
helper_text: "Máximo 100 caracteres"
max_text_length: 100Configuração de cores e estilos
O KivyMD permite personalizar facilmente toda a paleta de cores:
class MeuApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "Blue"
self.theme_cls.theme_style = "Dark"
return Builder.load_file("interface.kv")Desta forma, você pode adaptar completamente o visual às suas preferências ou identidade da marca.
Projeto prático: evoluindo sua lista de lembretes
Vamos transformar sua lista de lembretes básica em uma aplicação profissional. Aplicaremos tudo que aprendemos sobre Kivy Language Python e KivyMD de forma incremental.
Resultado anterior

Resultado esperado
Antes de começarmos a codar, veja exatamente o que vamos criar:

Teremos uma aplicação com:
- Cabeçalho com ícone e título estilizado;
- Campo de entrada com botão FAB (Floating Action Button);
- Lista de tarefas com ícones e botões de remoção;
- Tema claro/escuro alternável;
- Persistência automática de dados.
Estrutura base com KivyMD
Problema real: nossa lista atual usa componentes Kivy básicos que parecem desatualizados;
Solução: migrar para KivyMD mantendo a funcionalidade, mas com visual moderno;
Como funciona: é como reformar uma casa – mantemos a estrutura (funcionalidade), mas trocamos o acabamento (visual).
Implementação passo a passo:
Passo 1 – App base com KivyMD:
from kivymd.app import MDApp
from kivy.lang import Builder
class ListaLembretesApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "DeepPurple"
return Builder.load_file("interfaces/main.kv")
ListaLembretesApp().run()Passo 2 – Interface KV com cabeçalho estilizado:
MDScreen:
MDBoxLayout:
orientation: "vertical"
spacing: dp(8)
padding: dp(16)
# Cabeçalho com gradiente visual
MDCard:
size_hint_y: None
height: dp(100)
elevation: 4
md_bg_color: app.theme_cls.primary_color
radius: [15, 15, 15, 15]
MDBoxLayout:
orientation: "horizontal"
padding: dp(20)
spacing: dp(10)
MDIcon:
icon: "playlist-check"
size_hint_x: None
width: dp(40)
theme_icon_color: "Custom"
icon_color: 1, 1, 1, 1
pos_hint: {"center_y": 0.5}
MDLabel:
text: "To-Do List"
font_style: "H4"
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
bold: True
valign: "center"
MDIconButton:
icon: "theme-light-dark"
theme_icon_color: "Custom"
icon_color: 1, 1, 1, 1
pos_hint: {"center_y": 0.5}
on_press: app.alternar_tema()Campo de entrada profissional
Problema real: campo de texto simples não condiz com design moderno.
Solução: implementar campo com ícone e Floating Action Button.
Implementação passo a passo:
Passo 3 – Adicionar campo estilizado ao Kivy:
MDScreen:
MDBoxLayout:
MDCard:
...
# Adicionar após o cabeçalho
# Campo de entrada estilizado
MDCard:
size_hint_y: None
height: dp(80)
elevation: 2
radius: [12, 12, 12, 12]
MDBoxLayout:
orientation: "horizontal"
padding: dp(16)
spacing: dp(12)
MDTextField:
id: campo_lembrete
hint_text: "Add New Task"
multiline: False
font_size: dp(16)
on_text_validate: app.adicionar_lembrete()
MDFloatingActionButton:
icon: "plus"
md_bg_color: app.theme_cls.primary_color
size_hint: None, None
size: dp(45), dp(45)
pos_hint: {"center_y": 0.5}
elevation: 3
on_press: app.adicionar_lembrete()Passo 4 – Conectar lógica de adição:
class ListaLembretesApp(MDApp):
...
# Adicionar método à classe ListaLembretesApp
def adicionar_lembrete(self):
campo = self.root.ids.campo_lembrete
lista = self.root.ids.lista_lembretes
texto = campo.text.strip()
if texto:
item = LembreteItem(texto=texto)
lista.add_widget(item)
campo.text = ""
self.salvar_lembretes()Lista de tarefas interativa
Problema real: precisamos exibir e gerenciar os lembretes de forma visual.
Solução: implementar lista com ícones e botões de remoção usando componentes KivyMD.
Implementação passo a passo:
Passo 5 – Criar classe para itens da lista:
from kivymd.uix.list import OneLineAvatarIconListItem, IconLeftWidget, IconRightWidget
class LembreteItem(OneLineAvatarIconListItem):
def __init__(self, texto="", feito=False, **kwargs):
super().__init__(**kwargs)
self.texto_original = texto
self.feito = feito
# Ícone de tarefa à esquerda (checkbox)
self.icone = IconLeftWidget(
icon="checkbox-marked-circle-outline" if self.feito else "checkbox-blank-circle-outline"
)
self.icone.bind(on_release=self.toggle_feito)
self.add_widget(self.icone)
# Botão de lixeira (caso ainda queira manter exclusão manual)
botao = IconRightWidget(icon="delete-outline")
botao.bind(on_release=self.remover_item)
self.add_widget(botao)
self.atualizar_texto()Passo 6 – Adicionar área da lista ao Kivy:
MDScreen:
MDBoxLayout:
MDCard:
...
MDCard:
...
# Adicionar Lista de lembretes com estilo
MDCard:
elevation: 2
radius: [12, 12, 12, 12]
ScrollView:
MDList:
id: lista_lembretes
spacing: dp(2)Passo 7 – Completar lógica de adição e remoção:
# Adicionar método de remover item
class LembreteItem(OneLineAvatarIconListItem):
...
def atualizar_texto(self):
"""Atualiza o texto com ou sem risquinho"""
if self.feito:
self.text = f"[s]{self.texto_original}[/s]"
self.markup = True # permite usar tags [s][/s]
else:
self.text = self.texto_original
self.markup = False
def toggle_feito(self, *args):
"""Alterna entre concluído/não concluído"""
self.feito = not self.feito
self.icone.icon = (
"checkbox-marked-circle-outline" if self.feito else "checkbox-blank-circle-outline"
)
self.atualizar_texto()
MDApp.get_running_app().salvar_lembretes()
def remover_item(self, *args):
"""Remove completamente a tarefa"""
if self.parent:
self.parent.remove_widget(self)
MDApp.get_running_app().salvar_lembretes()Persistência e funcionalidades extras
Problema real: dados se perdem ao fechar o app, falta alternância de tema.
Solução: salvar dados em JSON e implementar toggle de tema.
Implementação passo a passo:
Passo 8 – Adicionar persistência:
import json
import os
class ListaLembretesApp(MDApp):
...
# Adicionar métodos à classe principal
def salvar_lembretes(self):
lista = self.root.ids.lista_lembretes
lembretes = [
{"texto": item.texto_original, "feito": item.feito}
for item in reversed(lista.children)
]
with open("lembretes.json", "w", encoding="utf-8") as f:
json.dump(lembretes, f, ensure_ascii=False, indent=2)
def on_start(self):
"""Carrega os lembretes salvos, se existirem"""
if os.path.exists("lembretes.json"):
with open("lembretes.json", "r", encoding="utf-8") as f:
for dic in json.load(f):
self.root.ids.lista_lembretes.add_widget(
LembreteItem(texto=dic["texto"], feito=dic["feito"])
)Passo 9 – Botão de alternância de tema:
class ListaLembretesApp(MDApp):
...
# Método para alternar tema
def alternar_tema(self):
self.theme_cls.theme_style = (
"Dark" if self.theme_cls.theme_style == "Light" else "Light"
)Validação: execute o app, adicione lembretes, feche e reabra – os dados devem persistir. O botão de tema deve alternar entre claro e escuro.
Checkpoint final
Agora você tem uma aplicação completamente profissional que:
- Visual: Design Material com cores harmoniosas;
- Funcional: adiciona, remove e persiste lembretes;
- Organizada: código separado em Python e Kivy;
- Moderna: componentes KivyMD e funcionalidades extras.
O mesmo conceito de lista de lembretes, mas com implementação de nível profissional.
Próximos passos: seu roadmap de evolução
Parabéns! Você transformou com sucesso um app básico em uma aplicação profissional. Atualmente, você domina Kivy Language Python e KivyMD, duas ferramentas fundamentais para desenvolvimento Kivy sério.
Suas conquistas atuais
Neste momento, você sabe como:
- Organizar código separando interface de lógica;
- Criar interfaces modernas com Material Design;
- Estruturar projetos Kivy de forma profissional;
- Implementar funcionalidades básicas de persistência.
Recursos para continuar evoluindo
Para aprofundar ainda mais seus conhecimentos:
Documentação oficial:
- KivyMD Gallery – Exemplos de todos os componentes.
- Kivy Garden – Widgets extras da comunidade.
Próximos desafios técnicos:
- Navegação entre telas com MDNavigationDrawer;
- Integração com APIs externas;
- Empacotamento com Buildozer para Android.
Trilha Python Office
Automatize tudo com Python e torne seu escritório muito mais eficiente! Manipule arquivos, crie relatórios automatizados e construa sistemas 100% personalizados usando apenas Python.
Comece agoraLembre-se: a jornada de um desenvolvedor Python nunca para. Cada projeto ensina algo novo, e cada desafio superado abre portas para possibilidades ainda maiores.
Arquivo main.py completo:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.list import OneLineAvatarIconListItem, IconLeftWidget, IconRightWidget
import json
import os
class LembreteItem(OneLineAvatarIconListItem):
def __init__(self, texto="", feito=False, **kwargs):
super().__init__(**kwargs)
self.texto_original = texto
self.feito = feito
# Ícone de tarefa à esquerda (checkbox)
self.icone = IconLeftWidget(
icon="checkbox-marked-circle-outline" if self.feito else "checkbox-blank-circle-outline"
)
self.icone.bind(on_release=self.toggle_feito)
self.add_widget(self.icone)
# Botão de lixeira (caso ainda queira manter exclusão manual)
botao = IconRightWidget(icon="delete-outline")
botao.bind(on_release=self.remover_item)
self.add_widget(botao)
self.atualizar_texto()
def atualizar_texto(self):
"""Atualiza o texto com ou sem risquinho"""
if self.feito:
self.text = f"[s]{self.texto_original}[/s]"
self.markup = True # permite usar tags [s][/s]
else:
self.text = self.texto_original
self.markup = False
def toggle_feito(self, *args):
"""Alterna entre concluído/não concluído"""
self.feito = not self.feito
self.icone.icon = (
"checkbox-marked-circle-outline" if self.feito else "checkbox-blank-circle-outline"
)
self.atualizar_texto()
MDApp.get_running_app().salvar_lembretes()
def remover_item(self, *args):
"""Remove completamente a tarefa"""
if self.parent:
self.parent.remove_widget(self)
MDApp.get_running_app().salvar_lembretes()
class ListaLembretesApp(MDApp):
# Método para alternar tema
def alternar_tema(self):
self.theme_cls.theme_style = (
"Dark" if self.theme_cls.theme_style == "Light" else "Light"
)
def salvar_lembretes(self):
lista = self.root.ids.lista_lembretes
lembretes = [
{"texto": item.texto_original, "feito": item.feito}
for item in reversed(lista.children)
]
with open("lembretes.json", "w", encoding="utf-8") as f:
json.dump(lembretes, f, ensure_ascii=False, indent=2)
def on_start(self):
"""Carrega os lembretes salvos, se existirem"""
if os.path.exists("lembretes.json"):
with open("lembretes.json", "r", encoding="utf-8") as f:
for dic in json.load(f):
self.root.ids.lista_lembretes.add_widget(
LembreteItem(texto=dic["texto"], feito=dic["feito"])
)
def adicionar_lembrete(self):
campo = self.root.ids.campo_lembrete
lista = self.root.ids.lista_lembretes
texto = campo.text.strip()
if texto:
item = LembreteItem(texto=texto)
lista.add_widget(item)
campo.text = ""
self.salvar_lembretes()
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "DeepPurple"
return Builder.load_file("interfaces/main.kv")
ListaLembretesApp().run()Arquivo interfaces/main.kv completo:
MDScreen:
MDBoxLayout:
orientation: "vertical"
spacing: dp(8)
padding: dp(16)
# Cabeçalho com gradiente visual
MDCard:
size_hint_y: None
height: dp(100)
elevation: 4
md_bg_color: app.theme_cls.primary_color
radius: [15, 15, 15, 15]
MDBoxLayout:
orientation: "horizontal"
padding: dp(20)
spacing: dp(10)
MDIcon:
icon: "playlist-check"
size_hint_x: None
width: dp(40)
theme_icon_color: "Custom"
icon_color: 1, 1, 1, 1
pos_hint: {"center_y": 0.5}
MDLabel:
text: "To-Do List"
font_style: "H4"
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
bold: True
valign: "center"
MDIconButton:
icon: "theme-light-dark"
theme_icon_color: "Custom"
icon_color: 1, 1, 1, 1
pos_hint: {"center_y": 0.5}
on_press: app.alternar_tema()
# Campo de entrada estilizado
MDCard:
size_hint_y: None
height: dp(80)
elevation: 2
radius: [12, 12, 12, 12]
MDBoxLayout:
orientation: "horizontal"
padding: dp(16)
spacing: dp(12)
MDTextField:
id: campo_lembrete
hint_text: "Add New Task"
multiline: False
font_size: dp(16)
on_text_validate: app.adicionar_lembrete()
MDFloatingActionButton:
icon: "plus"
md_bg_color: app.theme_cls.primary_color
size_hint: None, None
size: dp(45), dp(45)
pos_hint: {"center_y": 0.5}
elevation: 3
on_press: app.adicionar_lembrete()
MDCard:
elevation: 2
radius: [12, 12, 12, 12]
ScrollView:
MDList:
id: lista_lembretes
spacing: dp(2)
A ampla oferta de temas para o VS Code reforça a flexibilidade da IDE em adaptar a experiência de desenvolvimento às preferências do usuário, favorecendo conforto visual e engajamento sem impactar o desempenho. O ecossistema de extensões oferece opções consolidadas pela comunidade e mecanismos simples de instalação e descoberta, ampliando as possibilidades de personalização do ambiente de trabalho conforme diferentes perfis e contextos de uso.