Saudações a todos! Assim que a fumaça da discussão acalorada nos comentários do meu artigo, o
Kivy é uma estrutura de burro para o desenvolvimento de plataforma cruzada nº 1 e, entre outros,
um comentário digno de atenção , nós (
Mirimon ,
SeOd ) achamos que seria interessante para nós e leitores comparar o Kivy, O Xamarin.Forms e o React Native, escrevendo o mesmo aplicativo, acompanham-no com o artigo correspondente sobre Habré, explicam o
GitHub e honestamente informam quem enfrentou as dificuldades durante a implementação. Tendo se reunido no Telegram e discutido os detalhes, começamos a trabalhar.
Para essa comparação, decidimos escrever um agendador de tarefas simples com três telas. Hoje, cortar o estado dessas três plataformas, usando o exemplo de algo mais volumoso do que o exemplo que escolhemos, porque todos estão ocupados em seus projetos / no trabalho / em casa, leva muito tempo. Apesar da simplicidade de nosso aplicativo, ele permitirá demonstrar claramente os princípios de desenvolvimento de aplicativos em cada ambiente, trabalhar com dados, interface do usuário etc.
Três estruturas - um experimento. Xamarin.Forms. Parte 2Três estruturas - um experimento. Reagir nativo. Parte 3Este artigo é o primeiro do ciclo, então quero começar com o ToR, que esboçamos para nós mesmos, para que o resultado seja semelhante.
Opção TK:
- As notas devem ser estruturadas por projeto.
- As notas podem ser adicionadas por pessoas diferentes, portanto, o autor da nota deve ser indicado
- As notas dentro do projeto devem ser adicionadas / excluídas / editadas.
- As anotações devem ter o tamanho do conteúdo, mas não mais que 150 pixels
- A exclusão de notas deve ser feita através do menu de contexto da própria nota e através do furto
Um exemplo de interface do usuário deve ser algo como isto:

Antes de começar, uma pequena ajuda no Kivy:O Kivy é uma estrutura gráfica multiplataforma escrita na linguagem de programação Python / Cython, baseada no OpenGL ES 2, com o objetivo de criar interfaces de usuário modernas, mais focadas no trabalho com dispositivos de toque. Os aplicativos Kivy são executados em plataformas como Linux, OS X, Windows, Android, iOS e Rapberry Pi. No desenvolvimento, você tem acesso a uma ampla variedade de bibliotecas Python, desde Requests a NumPy e OpenCV. O Kivy tem acesso a quase todas as APIs móveis nativas (GPS, Câmera, Acelerômetro, API do Google para Android), através do PyJNIus (Android) e PyOBJus (iOS), que agrupam automaticamente o código Java / Objective-C no Python .
Kivy é rápido. Isso se aplica ao desenvolvimento e à velocidade de execução de aplicativos. Todas as funções críticas são implementadas no nível C. Kivy também usa a GPU sempre que faz sentido. A GPU faz a maior parte do trabalho, aumentando significativamente o desempenho.
Kivy é muito flexível. Isso significa que o rápido desenvolvimento do Kivy permite que você se adapte instantaneamente às novas tecnologias. Os desenvolvedores do Kivy adicionaram repetidamente suporte a novos dispositivos externos e protocolos de software, às vezes antes mesmo do lançamento. O Kivy pode ser usado em conjunto com muitas soluções de terceiros diferentes. Por exemplo, no Windows, o Kivy suporta WM_TOUCH, o que significa que qualquer dispositivo com os drivers do Windows 7 Pen & Touch funcionará com o Kivy. No OS X, você pode usar dispositivos Apple com suporte a Multi-Touch, como trackpads e mouses. No Linux, você pode usar eventos de entrada de entrada HID. Além disso, o Kivy suporta o TUIO (Objetos de interface do usuário tangíveis) e várias outras fontes de entrada.
Você pode escrever um aplicativo simples com algumas linhas de código. Os programas Kivy são criados usando a linguagem de programação Python, que é incrivelmente versátil e poderosa, mas fácil de usar. Além disso, os desenvolvedores do Kivy criaram sua própria linguagem de marcação da GUI para criar sofisticadas GUIs personalizadas. Esse idioma permite que você configure, conecte e organize rapidamente os elementos do aplicativo.
E, sim, Kivy é totalmente gratuito. Você pode usá-lo em qualquer lugar! Em um produto comercial ou em código aberto. Darei todo o código do aplicativo e mostrarei com detalhes suficientes como esses ou esses elementos são implementados no desenvolvimento para plataformas móveis. Como IDE, eu sempre uso o
PyCharm , que suporta perfeitamente a sintaxe da
linguagem Kv - uma linguagem DSL especial na qual a representação da interface do usuário do seu aplicativo é escrita. O esqueleto do aplicativo foi criado usando o utilitário do console
CreatorKivyProject , que fornece telas básicas usando o modelo MVVM.
A pasta
baseclass contém a lógica dos widgets e controles implementados na linguagem de programação Python, nos arquivos de descrição da interface
kv na
linguagem Kv . O diretório
applibs é usado para bibliotecas de terceiros, na pasta de
dados há conteúdo de mídia, bancos de dados e outros dados. O arquivo
main.py é o ponto de entrada do aplicativo. Ele não faz nada além de iniciar a interface do usuário
TodoList (). Run () renderiza, apanha um erro se ocorrer e exibe uma janela para enviar um relatório de erro, criado automaticamente pelo utilitário
CreatorKivyProject , não tem nada a ver com escrever nosso aplicativo e, portanto, não é considerado.
O arquivo
todolist.py com o código do programa implementa a classe
TodoList , que carrega os layouts de interface, inicializa suas instâncias, monitora os eventos das teclas de atalho do dispositivo e retorna nossa primeira tela, listada no gerenciador de atividades. Após
TodoList (). Run () , a função de
construção é chamada e retorna o widget que será exibido na tela.
Por exemplo, o código para um programa simples que exibe uma única tela com uma imagem terá a seguinte aparência:
E aqui está o diagrama da nossa classe de aplicativo:
Nosso aplicativo consiste em apenas três
atividades , o gerenciador de tela (
ScreenMenager ), que retornamos às funções de
construção , é responsável pela
alternância :
#:import ListProjectsActivity libs.uix.baseclass.ListProjectsActivity.ListProjectsActivity #:import ListNotesActivity libs.uix.baseclass.ListNotesActivity.ListNotesActivity #:import AddNewNoteActivity libs.uix.baseclass.AddNewNoteActivity.AddNewNoteActivity #:import ActivityManager libs.uix.baseclass.ActivityManager.ActivityManager <RootScreen@BoxLayout>: orientation: 'vertical' spacing: dp(2) ActivityManager: id: activityManager ListProjectsActivity: id: listProjectsActivity ListNotesActivity: id: listNotesActivity AddNewNoteActivity: id: addNewNoteActivity
Quando o aplicativo for iniciado, a atividade especificada no ActivityManager primeiro será instalada. No nosso caso, é
ListProjectsActivity . No aplicativo para listas de projetos e tarefas, usei o
ScrollView . Embora tenha sido mais correto -
RecycleView . Porque o primeiro, se houver mais de cem postagens e projetos, não será possível. Mais precisamente, levará muito tempo para renderizar listas.
O RecycleView permite exibir listas de qualquer tamanho quase instantaneamente. Mas como em qualquer caso, com listas grandes, você teria que usar o carregamento dinâmico de dados em uma lista ou paginação, mas isso não foi discutido no TOR, usei o
ScrollView . A segunda razão é que eu estava com preguiça de refazer listas no
RecycleView (e é
fundamentalmente diferente em uso do
ScrollView ), e não houve muito tempo, porque todo o aplicativo foi gravado em quatro horas em intervalos de fumaça e intervalos de café.
A tela inicial com uma lista de projetos (ListProjectsActivity.kv e ListProjectsActivity.py) tem a seguinte aparência:
Como o layout da tela ListProjectsActivity já é mostrado na tela, mostrarei como fica sua classe de controle:
# -*- coding: utf-8 -*- from kivy.app import App from kivy.uix.screenmanager import Screen as Activity from libs.uix.baseclass.InputDialog import InputDialog from . ProjectItem import ProjectItem class ListProjectsActivity(Activity): objApp = App.get_running_app() def setListProjects(self, objApp): for nameProject in objApp.dataProjects.keys(): self.ids.layoutContainer.add_widget(ProjectItem(projectName=nameProject)) def createNewProject(self, projectName): if projectName and not projectName.isspace(): self.ids.layoutContainer.add_widget(ProjectItem(projectName=projectName)) self.objApp.addProjectInBase(projectName) def deleteProject(self, instance): for projectName in self.objApp.dataProjects: if instance.projectName == projectName: self.objApp.deleteProjectFromBase(projectName) break def showDialogCreateProject(self, *args): InputDialog( title=' ', hintText=' ', textButtonCancel='', textTuttonOk='', eventsCallback=self.createNewProject).show()
Chamada na caixa de diálogo:
No trabalho, chamar a janela e criar um novo projeto ficará assim:
Não vou me debruçar sobre a questão sobre dados de aplicativos, porque os dados são um dicionário regular do formulário
{"Name Project": [{"pathToAvatar": "", "nameDate": "", "nameAuthor": "", "textNote": ""}]}
e que é armazenado no diretório de
dados como um arquivo json simples.
Vamos ver qual é o item com o nome do projeto e como usar o Kivy para excluir um item da lista com um simples toque de dedo? Para fazer isso, devemos herdar o comportamento do widget na lista da classe
SwipeBehavior da biblioteca
SwipeToDelete :
ProjectItemActivity.py from kivy.properties import StringProperty from kivy.uix.boxlayout import BoxLayout from libs.applibs.swipetodelete import SwipeBehavior class ProjectItemActivity(SwipeBehavior, BoxLayout): projectName = StringProperty() def on_touch_down(self, touch): if self.collide_point(touch.x, touch.y): self.move_to = self.x, self.y return super(ProjectItemActivity, self).on_touch_down(touch) def on_touch_move(self, touch): if self.collide_point(touch.x, touch.y): self.reduce_opacity() return super(ProjectItemActivity, self).on_touch_move(touch) def on_touch_up(self, touch): if self.collide_point(touch.x, touch.y): self.check_for_left() self.check_for_right() return super(ProjectItemActivity, self).on_touch_up(touch)
E a descrição do item do projeto na marcação Kv:
ProjectItemActivity.kv <ProjectItemActivity>: swipe_rectangle: self.x, self.y , self.width, self.height swipe_timeout: 1000000 swipe_distance: 1 event_after_swipe: app.listActivity.deleteProject OneLineListItem: text: root.projectName on_press: app.listActivity.setNotesProject(root.projectName)
Em geral, todo widget no Kivy possui um método
on_touch com o qual você pode capturar todos os eventos que ocorrem na tela. Aqui está uma pequena parte da lista de eventos disponíveis:
['double_tap_time', 'grab_state', 'is_double_tap', 'is_mouse_scrolling', 'is_touch', 'is_triple_tap', 'move', 'push', 'push_attrs', 'push_attrs_stack', 'scale_for_screen', 'time_end', 'time_start', 'time_update', 'triple_tap_time', 'ungrab', 'update_time_end']
Implementando o menu de contexto para Android ...
Também não houve problemas aqui, pois este é apenas um widget padrão do DropDown. Graças ao fato de você poder personalizar todos os widgets e controles no Kivy, tanto quanto sua imaginação permitir, eu consegui facilmente um menu bonito. À esquerda está o DropDown básico, à direita é meu:
Layout da lista do menu de contexto:
ContextMenuAndroidActivity.kv #:import MDSeparator libs.applibs.kivymd.card.MDSeparator #:import MenuItem libs.applibs.animdropdown.MenuItem <ContextMenuAndroidActivity>: MenuItem: text: '' menu: root on_press: root.tapOnItem(self.text) MDSeparator: MenuItem: text: '' menu: root on_press: root.tapOnItem(self.text)
A parte do software do menu de contexto:
ContextMenuAndroidActivity.kv from kivy.app import App from kivy.clock import Clock from libs.applibs.animdropdown import AnimMenuDropDown class ContextMenuAndroidActivity(AnimMenuDropDown): def tapOnItem(self, textItem): objApp = App.get_running_app() if textItem == '': objApp.listActivity.deletePost() else: objApp.activityManager.current = 'add new note activity' Clock.schedule_once(objApp.addNewNoteActivity.editNote, .5)
Em seguida, importamos o botão
MenuDropDown da biblioteca
animdropdown , passamos a ele o objeto do nosso menu de contexto como parâmetro e, depois disso, adicionamos esse botão à tela que precisamos. Em nossa aplicação, este é o botão à direita no cartão de nota:
Notas do cartão de atividade de marcação:
Classe base
NoteActivity :
from kivy.app import App from kivy.properties import StringProperty from kivy.uix.boxlayout import BoxLayout from libs.applibs.animdropdown import MenuButton from libs.applibs.swipetodelete import SwipeBehavior from . ContextMenu import ContextMenu class NoteActivity(SwipeBehavior, BoxLayout): nameDate = StringProperty() textNote = StringProperty() pathToAvatar = StringProperty() def __init__(self, **kwargs): super(NoteActivity, self).__init__(**kwargs) self.objApp = App.get_running_app() menuButton = MenuButton( dropdown_cls=ContextMenu, icon='dots-vertical', _on_dropdown_fnc=self.setCurrentPost) self.ids.titleBox.add_widget(menuButton) def setCurrentPost(self, *args): self.objApp.listNotesActivity.checkCurentPost = self
Implementação de software do
ListNotesActivity :
Como gerenciar a atividade do aplicativo? Para mudar de uma atividade para outra, devemos indicar ao gerente de tela o nome da nova atividade:
class ListNotesActivity(Activity): ... def addNewNote(self, *args): self.objApp.activityManager.current = 'add new note activity'
... onde
'adicionar nova atividade da nota' é o nome da atividade para adicionar uma nova nota.
Tela e layout da
atividade AddNewNoteActivity :
Classe base:
from kivy.app import App from kivy.animation import Animation from kivy.uix.screenmanager import Screen as Activity from kivy.metrics import dp from libs.uix.baseclass.NoteActivity import NoteActivity class AddNewNoteActivity(Activity): objApp = None edit = False oldTextNote = '' def animationButton(self): self.objApp = App.get_running_app() self.ids.toolBar.title = self.objApp.listNotesActivity.ids.toolBar.title Animation(size=(dp(56), dp(56)), d=.5, t='in_out_cubic').start(self.ids.floatingButton) def addNewNotes(self, textNote): if self.edit: nameProject = self.ids.toolBar.title self.objApp.addEditNoteInBase(nameProject, textNote, self.oldTextNote) self.objApp.activityManager.backActivity('list notes activity', self.ids.floatingButton) self.objApp.listNotesActivity.checkCurentPost.textNote = textNote self.edit = False return self.objApp.listNotesActivity.ids.layoutContainer.add_widget( NoteActivity( textNote=textNote, nameDate='%s\n%s' % ( self.objApp.nameAuthor, self.objApp.getDate()), pathToAvatar='data/images/avatar.png')) self.objApp.addNoteInBase(self.ids.toolBar.title, textNote, 'data/images/avatar.png') def editNote(self, interval): self.edit = True self.ids.textInput.text = self.objApp.listNotesActivity.checkCurentPost.textNote self.oldTextNote = self.ids.textInput.text
Para animar o botão, usei o evento
on_enter , que é gerado quando a Atividade é instalada na tela:
Na marcação:
<AddNewNoteActivity> on_enter: root.animationButton()
No código Python:
class AddNewNoteActivity(Activity): def animationButton(self): Animation(size=(dp(56), dp(56)), d=.5, t='in_out_cubic').start(self.ids.floatingButton)
Diferentemente do Xamarin.Forms, a interface do usuário no Kivy terá a mesma aparência em todos os lugares. Portanto, se você estiver escrevendo um aplicativo para duas plataformas (Android e iOS), leve isso em consideração ao marcar a interface e especificar propriedades para widgets. Ou faça duas marcações para duas plataformas (a lógica permanece inalterada). Isso é uma vantagem, já que a renderização da interface do usuário e os eventos são independentes dos recursos da plataforma, você não usa APIs nativas para controlar essas ações, o que permite que seu aplicativo seja executado em praticamente qualquer plataforma sem problemas. Todos os gráficos são renderizados usando chamadas OpenGL e SDL2 nativas na GPU, o que permite desenhar rapidamente menus, botões e outros encantos da interface gráfica, incluindo gráficos 2D e 3D.
Este aplicativo usa a UI do Android MaterialDesign. Por exemplo, meu último projeto teve uma interface adaptável:
Aqui está uma demonstração das possibilidades no estilo do design de materiais:
Como eu disse, o Kivy não usa APIs nativas para renderizar a interface do usuário; portanto, você pode emular vários modelos de dispositivos e plataformas usando o módulo de
tela . É suficiente executar seu projeto com os parâmetros necessários para que a janela do aplicativo testado seja aberta no computador como se estivesse sendo executado em um dispositivo real. Parece estranho, mas como o Kivy abstrai da plataforma na renderização da interface do usuário, isso elimina a necessidade de emuladores pesados e lentos para testes. Isso se aplica apenas à interface do usuário. Por exemplo, o aplicativo de teste descrito neste artigo foi testado com os parâmetros
-m tela: droid2, portrait, scale = 0,75, que um a um corresponde ao meu dispositivo real.
Lista completa de parâmetros do módulo de tela: O que pode ser dito em conclusão? Kivy é bom? Sem dúvida bom! Se você conhece a maravilhosa linguagem de programação Python, pode criar facilmente aplicativos para plataformas móveis (e não apenas) com a não menos maravilhosa estrutura Kivy.
Vantagens de desenvolver aplicativos usando a estrutura Kivy:- Como estamos lidando com Python, a velocidade de desenvolvimento de aplicativos é várias vezes mais rápida que a velocidade de desenvolvimento em qualquer outra linguagem ou estrutura de programação.
- Megatons de bibliotecas Python prontas que você pode usar em seus projetos: OpenCV, Django, Flask, NumPy, ffmpeg, sqlite3, lxml e milhares de outras.
- Como o Kivy usa OpenGL e GPU para renderizar gráficos, bem como seus próprios widgets e controles, a velocidade de renderização da interface do usuário é muito alta e você fica completamente aliviado da dor de cabeça, presente em outras estruturas que precisam entrar na parte nativa para implementar algumas partes da interface.
- Você usa o nativo apenas onde precisa acessar recursos específicos da plataforma que simplesmente não podem existir em uma estrutura verdadeiramente multiplataforma: por exemplo, acesso à geolocalização, acesso à câmera, tecnologia BlueTooth ...
Implementando o acesso à API nativa do Android para obter o IMEI e o modelo do dispositivo usando o PyJnius:
def _get_model_android(): from jnius import autoclass Build = autoclass('android.os.Build') return str(Build.DEVICE) def _get_imei_android(): from jnius import autoclass Service = autoclass('org.renpy.android.PythonActivity').mActivity Context = autoclass('android.content.Context') TelephonyManager = Service.getSystemService(Context.TELEPHONY_SERVICE) return str(TelephonyManager.getDeviceId())
Por exemplo, uma implementação de dispositivos IMEI receptores nativos em Java:
import android.content.Context; import android.telephony.TelephonyManager; public class GetImeiAndroid { public String getImeiAndroid() { TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String IMEINumber = tm.getDeviceId(); return IMEINumber; } }
- Você pode usar bibliotecas jar de terceiros em seus projetos quando se trata do Android.
- Você detém completamente todos os eventos que ocorrem na tela: toque, multitoque, furto, perfuração e outros eventos sem ir para o nativo, portanto, isso é parte integrante do Kivy.
Recursos do Kivy nos dispositivos Touch:
Apesar de todas as vantagens, o Kivy tem várias desvantagens:- A velocidade do "cold start", ou seja, o primeiro lançamento do aplicativo a partir do momento em que todas as bibliotecas são implantadas, é bastante longa. Os subsequentes são comuns, mas mais longos que o nativo, dependendo da carga do processador do dispositivo móvel.
- Trabalhe com listas. Você pode exibir uma lista com um tamanho de 100.000 itens em meio segundo (por exemplo, cartões de usuário, mostruário, cotações), mas com uma condição - todos os cartões devem ter a mesma altura. Se você exibir uma lista de, por exemplo, citações, com uma quantidade desconhecida de texto com antecedência, mas na íntegra, ao mesmo tempo, mais de dez pontos não poderão ser mostrados, pois isso levará de 10 a 15 segundos. Nesse caso, você precisará carregar de 10 a 15 itens cada um enquanto percorre a lista.
- É impossível exibir texto que exceda 6500 caracteres (3,5 páginas de texto impresso) - obtemos uma tela preta. Isso é resolvido quebrando o texto e colando-o, o que ainda parece uma muleta. No entanto, não está claro para quem você gostaria de enviar uma quantidade de texto por vez. Especialmente quando se trata de plataformas móveis.
→
Mais artigos sobre KivyUma máquina virtual (a primeira postagem do ZenCODE) dos desenvolvedores do Kivy está pronta e configurada para criar projetos para os dois ramos do Python.