Введение
Kivy — это мощный, открытый фреймворк для создания графических интерфейсов и кроссплатформенных приложений на языке Python. Он поддерживает Android, iOS, Windows, Linux и macOS, что делает его отличным выбором для разработки мобильных и настольных приложений с единым кодом.
Библиотека предоставляет инструменты для построения адаптивных интерфейсов, управления вводом с клавиатуры, мыши, сенсора и мультитача, а также включает собственный язык разметки KV для отделения логики и UI. Kivy использует OpenGL для рендеринга, что обеспечивает высокую производительность и плавную анимацию.
Что такое Kivy и его особенности
Ключевые преимущества фреймворка
Kivy выделяется среди других библиотек для создания графических интерфейсов несколькими важными особенностями. Фреймворк полностью написан на Python с использованием Cython для критически важных компонентов, что обеспечивает высокую производительность.
Основные особенности включают:
- Нативная поддержка мультитача и жестов
- Аппаратное ускорение через OpenGL ES 2.0
- Автоматическое масштабирование интерфейса под разные разрешения экранов
- Модульная архитектура с возможностью расширения
- Встроенная поддержка анимаций и эффектов
Архитектура фреймворка
Kivy построен на модульной архитектуре, где каждый компонент может быть заменен или расширен. Ядро фреймворка состоит из нескольких основных модулей: Clock для управления временем, Window для работы с окном приложения, Factory для создания объектов и Cache для оптимизации производительности.
Установка и настройка
Базовая установка Kivy
pip install kivy
Для разработки под Android потребуется дополнительная утилита buildozer:
pip install buildozer
Установка зависимостей для разных платформ
Windows
pip install kivy[base,media]
Linux (Ubuntu/Debian)
sudo apt-get install python3-kivy
macOS
brew install pkg-config sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer
pip install kivy
Проверка корректности установки
После установки можно проверить работоспособность с помощью простого теста:
import kivy
print(kivy.__version__)
Создание первого приложения
Простейшее Kivy-приложение
from kivy.app import App
from kivy.uix.button import Button
class MyApp(App):
def build(self):
return Button(text="Нажми меня")
MyApp().run()
Запуск этого кода откроет окно с кнопкой, которая займет всю область окна.
Структура Kivy-приложения
Каждое приложение в Kivy имеет следующую базовую структуру:
- App — главный класс, который запускает и управляет приложением
- Widget — базовый элемент интерфейса, от которого наследуются все компоненты
- Layout — контейнеры для организации виджетов (BoxLayout, GridLayout и другие)
- Screen — отдельные экраны приложения для навигации
Жизненный цикл приложения
Kivy-приложение проходит через несколько стадий:
- Инициализация App класса
- Вызов метода build() для создания интерфейса
- Запуск основного цикла событий
- Обработка пользовательского ввода
- Завершение работы при закрытии
Основные компоненты и виджеты
Базовые виджеты пользовательского интерфейса
Label — отображение текста
from kivy.uix.label import Label
label = Label(text='Привет, мир!',
font_size='20sp',
color=[1, 0, 0, 1]) # красный цвет
Button — интерактивная кнопка
from kivy.uix.button import Button
button = Button(text='Нажми меня',
size_hint=(0.5, 0.3),
pos_hint={'center_x': 0.5, 'center_y': 0.5})
TextInput — поле ввода текста
from kivy.uix.textinput import TextInput
text_input = TextInput(text='Введите текст',
multiline=False,
font_size=16)
Контейнеры и компоновщики
BoxLayout — линейное расположение
from kivy.uix.boxlayout import BoxLayout
layout = BoxLayout(orientation='vertical', spacing=10, padding=20)
layout.add_widget(Label(text='Первый элемент'))
layout.add_widget(Button(text='Кнопка'))
GridLayout — табличное расположение
from kivy.uix.gridlayout import GridLayout
grid = GridLayout(cols=2, rows=2, spacing=[10, 10])
for i in range(4):
grid.add_widget(Button(text=f'Кнопка {i+1}'))
FloatLayout — свободное позиционирование
from kivy.uix.floatlayout import FloatLayout
float_layout = FloatLayout()
btn1 = Button(text='Левый верх',
size_hint=(0.3, 0.2),
pos_hint={'x': 0, 'top': 1})
float_layout.add_widget(btn1)
Язык разметки KV
Создание интерфейса с использованием KV
KV-язык позволяет отделить описание интерфейса от логики приложения, делая код более читаемым и поддерживаемым.
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MainWidget(BoxLayout):
def button_pressed(self):
print("Кнопка была нажата!")
class MyKvApp(App):
def build(self):
return MainWidget()
MyKvApp().run()
mykv.kv
<MainWidget>:
orientation: 'vertical'
padding: 20
spacing: 10
Label:
text: 'Добро пожаловать в Kivy!'
font_size: '24sp'
size_hint_y: 0.3
Button:
text: 'Нажми меня'
size_hint_y: 0.2
on_press: root.button_pressed()
TextInput:
hint_text: 'Введите сообщение'
size_hint_y: 0.2
Синтаксис и возможности KV
Привязка свойств
<MyWidget>:
Button:
text: 'Счетчик: ' + str(root.counter)
on_press: root.counter += 1
Использование идентификаторов
<MyWidget>:
TextInput:
id: text_input
Button:
text: 'Очистить'
on_press: text_input.text = ''
Обработка событий и взаимодействие
Система событий в Kivy
Kivy использует мощную систему событий, основанную на свойствах и сигналах. Каждый виджет может генерировать события и реагировать на них.
Обработка пользовательского ввода
Обработка нажатий мыши и касаний
class TouchWidget(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
print(f"Касание в точке: {touch.pos}")
return True
return super().on_touch_down(touch)
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
print(f"Движение в точке: {touch.pos}")
Обработка событий клавиатуры
from kivy.core.window import Window
class KeyboardWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._keyboard = Window.request_keyboard(
self._keyboard_closed, self)
self._keyboard.bind(on_key_down=self._on_keyboard_down)
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
print(f'Нажата клавиша: {keycode[1]}')
Привязка событий к виджетам
Программная привязка
button = Button(text='Клик')
button.bind(on_press=self.on_button_click)
def on_button_click(self, instance):
print(f"Нажата кнопка: {instance.text}")
Привязка через KV
Button:
text: 'Кнопка'
on_press: app.handle_button_press(self)
on_release: app.handle_button_release(self)
Работа с графикой и Canvas
Рисование на Canvas
Canvas — это низкоуровневый интерфейс для рисования в Kivy. Каждый виджет имеет три canvas: before (рисуется перед содержимым), canvas (основной) и after (рисуется после содержимого).
from kivy.graphics import Color, Rectangle, Line, Ellipse
class PaintWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(1, 0, 0, 1) # красный цвет
self.rect = Rectangle(pos=(50, 50), size=(100, 100))
Color(0, 1, 0, 1) # зеленый цвет
Line(points=[10, 10, 200, 100, 300, 200], width=2)
Анимации и переходы
Простая анимация
from kivy.animation import Animation
# Анимация перемещения
anim = Animation(x=200, y=200, duration=2)
anim.start(widget)
# Последовательная анимация
anim1 = Animation(x=100, duration=1)
anim2 = Animation(y=100, duration=1)
anim_sequence = anim1 + anim2
anim_sequence.start(widget)
Сложные переходы
from kivy.animation import Animation
from kivy.uix.widget import Widget
class AnimatedWidget(Widget):
def animate_rotation(self):
# Вращение с эффектом пружины
anim = Animation(rotation=360, duration=2, t='out_bounce')
anim.bind(on_complete=self.reset_rotation)
anim.start(self)
def reset_rotation(self, animation, widget):
widget.rotation = 0
Мультимедиа и ресурсы
Работа с изображениями
from kivy.uix.image import Image
# Загрузка изображения из файла
img = Image(source='path/to/image.jpg')
# Изображение с настройками
img = Image(source='logo.png',
size_hint=(0.5, 0.5),
pos_hint={'center_x': 0.5, 'center_y': 0.5},
allow_stretch=True,
keep_ratio=True)
Воспроизведение звука
from kivy.core.audio import SoundLoader
class AudioWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.sound = SoundLoader.load('sound.wav')
def play_sound(self):
if self.sound:
self.sound.play()
Работа с видео
from kivy.uix.videoplayer import VideoPlayer
video = VideoPlayer(source='movie.mp4',
state='play',
options={'allow_stretch': True})
Навигация между экранами
ScreenManager для управления экранами
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class GameScreen(Screen):
pass
class MyScreenApp(App):
def build(self):
sm = ScreenManager(transition=SlideTransition())
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
sm.add_widget(GameScreen(name='game'))
return sm
Переходы между экранами в KV
<MenuScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Играть'
on_press: root.manager.current = 'game'
Button:
text: 'Настройки'
on_press: root.manager.current = 'settings'
<SettingsScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'Экран настроек'
Button:
text: 'Назад'
on_press: root.manager.current = 'menu'
Адаптивная верстка и responsive design
Принципы адаптивного дизайна в Kivy
Kivy предоставляет несколько механизмов для создания адаптивных интерфейсов:
Использование size_hint
# Виджет займет 50% ширины и 30% высоты родителя
widget = Button(text='Адаптивная кнопка',
size_hint=(0.5, 0.3))
# Фиксированная ширина, адаптивная высота
widget = Button(text='Полуфиксированная',
size_hint=(None, 0.3),
width=200)
Responsive layouts
<ResponsiveLayout>:
cols: 2 if root.width > root.height else 1
Button:
text: 'Кнопка 1'
Button:
text: 'Кнопка 2'
Работа с разными разрешениями экранов
from kivy.metrics import dp, sp
from kivy.core.window import Window
class ResponsiveWidget(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Window.bind(size=self.on_window_resize)
self.update_layout()
def on_window_resize(self, window, width, height):
self.update_layout()
def update_layout(self):
if Window.width < dp(600):
self.orientation = 'vertical'
else:
self.orientation = 'horizontal'
Сборка мобильных приложений
Настройка Buildozer для Android
Инициализация проекта
buildozer init
Основные настройки в buildozer.spec
[app]
title = My Kivy App
package.name = mykivyapp
package.domain = org.example
version = 0.1
requirements = python3,kivy,plyer
[buildozer]
log_level = 2
[app:android]
android.permissions = INTERNET,WRITE_EXTERNAL_STORAGE
android.api = 31
android.minapi = 21
android.ndk = 25b
Сборка APK
# Отладочная сборка
buildozer android debug
# Релизная сборка
buildozer android release
# Установка на подключенное устройство
buildozer android deploy run
Подготовка к публикации в Google Play
Подписание APK
# Создание keystore
keytool -genkey -v -keystore my-release-key.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
# Подписание APK
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore my_app-release-unsigned.apk my-alias
Оптимизация приложения
# Минификация кода и ресурсов
from kivy.logger import Logger
Logger.setLevel('WARNING') # Отключение отладочных сообщений
# Компрессия изображений
# Использование WebP формата вместо PNG
# Удаление неиспользуемых ресурсов
Тестирование и отладка
Отладочные инструменты Kivy
Встроенный инспектор
from kivy.modules import inspector
from kivy.config import Config
Config.set('modules', 'inspector', '')
Логирование
from kivy.logger import Logger
Logger.info('Application: Приложение запущено')
Logger.warning('Application: Предупреждение')
Logger.error('Application: Ошибка в работе')
Тестирование пользовательского интерфейса
import unittest
from kivy.tests.common import GraphicUnitTest
class ButtonTest(GraphicUnitTest):
def test_button_press(self):
from kivy.uix.button import Button
button = Button(text='Test')
self.render(button)
# Симуляция нажатия
button.dispatch('on_press')
# Проверка результата
self.assertIsNotNone(button.last_touch)
Работа с базами данных и API
Интеграция с SQLite
import sqlite3
from kivy.storage.jsonstore import JsonStore
class DatabaseManager:
def __init__(self, db_path):
self.db_path = db_path
self.init_database()
def init_database(self):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
''')
conn.commit()
conn.close()
def add_user(self, name, email):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('INSERT INTO users (name, email) VALUES (?, ?)',
(name, email))
conn.commit()
conn.close()
Работа с REST API
import requests
from kivy.network.urlrequest import UrlRequest
class ApiManager:
def __init__(self, base_url):
self.base_url = base_url
def get_data(self, endpoint, callback):
url = f"{self.base_url}/{endpoint}"
UrlRequest(url, on_success=callback, on_error=self.on_error)
def on_error(self, request, error):
print(f"Ошибка API: {error}")
Расширенные возможности
Работа с сенсорами устройства
from plyer import accelerometer, gyroscope, compass
class SensorManager:
def __init__(self):
self.accelerometer_enabled = False
def enable_accelerometer(self):
accelerometer.enable()
self.accelerometer_enabled = True
def get_acceleration(self):
if self.accelerometer_enabled:
return accelerometer.acceleration
return None
Использование камеры
from kivy.uix.camera import Camera
class CameraWidget(Camera):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.resolution = (640, 480)
self.play = True
def take_picture(self):
timestamp = time.strftime('%Y%m%d_%H%M%S')
filename = f'IMG_{timestamp}.jpg'
self.export_to_png(filename)
Работа с файловой системой
from kivy.utils import platform
from kivy.storage.jsonstore import JsonStore
import os
class FileManager:
def __init__(self):
if platform == 'android':
from android.permissions import request_permissions, Permission
request_permissions([Permission.WRITE_EXTERNAL_STORAGE])
self.app_dir = '/sdcard/MyKivyApp'
else:
self.app_dir = os.path.expanduser('~/MyKivyApp')
os.makedirs(self.app_dir, exist_ok=True)
def save_settings(self, settings):
store = JsonStore(os.path.join(self.app_dir, 'settings.json'))
for key, value in settings.items():
store.put(key, value=value)
Полная таблица методов и функций Kivy
| Категория | Класс/Функция | Описание | Основные методы |
|---|---|---|---|
| Приложение | App | Базовый класс приложения | build(), run(), stop(), get_running_app() |
| Clock | Управление временем | schedule_once(), schedule_interval(), unschedule() | |
| Config | Конфигурация приложения | get(), set(), write() | |
| Виджеты | Widget | Базовый класс всех виджетов | add_widget(), remove_widget(), clear_widgets() |
| Label | Отображение текста | text, font_size, color, halign, valign | |
| Button | Интерактивная кнопка | on_press, on_release, state | |
| TextInput | Поле ввода текста | text, hint_text, password, multiline | |
| Image | Отображение изображений | source, texture, reload() | |
| Slider | Ползунок для выбора значений | value, min, max, step, on_value | |
| ProgressBar | Индикатор прогресса | value, max | |
| Switch | Переключатель | active, on_active | |
| CheckBox | Флажок | active, group, on_active | |
| Spinner | Выпадающий список | text, values, on_text | |
| Контейнеры | BoxLayout | Линейное расположение | orientation, spacing, padding |
| GridLayout | Табличное расположение | cols, rows, spacing | |
| FloatLayout | Свободное позиционирование | size_hint, pos_hint | |
| RelativeLayout | Относительное позиционирование | to_parent, to_widget | |
| StackLayout | Стековое расположение | orientation, spacing | |
| AnchorLayout | Якорное расположение | anchor_x, anchor_y | |
| ScatterLayout | Масштабируемое расположение | do_rotation, do_translation | |
| Экраны | ScreenManager | Управление экранами | current, transition, add_widget() |
| Screen | Отдельный экран | name, manager | |
| Переходы | SlideTransition | Скользящий переход | direction, duration |
| FadeTransition | Переход с затуханием | duration | |
| SwapTransition | Мгновенный переход | - | |
| WipeTransition | Переход с вытиранием | direction | |
| События | Touch | Объект касания/клика | pos, grab_current, grab() |
| KeyboardGuardian | Управление клавиатурой | request_keyboard() | |
| Графика | Canvas | Холст для рисования | add(), remove(), clear() |
| Color | Цвет | rgba, rgb, hsv | |
| Rectangle | Прямоугольник | pos, size, texture | |
| Ellipse | Эллипс/круг | pos, size, angle_start, angle_end | |
| Line | Линия | points, width, cap, joint | |
| Анимация | Animation | Анимация свойств | start(), stop(), cancel() |
| Transition | Переходы анимации | in_quad, out_bounce, in_out_sine | |
| Ввод/Вывод | FileChooser | Выбор файлов | path, filters, on_selection |
| Popup | Всплывающее окно | title, content, size_hint | |
| ModalView | Модальное окно | auto_dismiss, on_open, on_dismiss | |
| Мультимедиа | SoundLoader | Загрузка звука | load(), play(), stop() |
| VideoPlayer | Видеоплеер | source, state, volume | |
| Camera | Камера | resolution, play, export_to_png() | |
| Хранение | JsonStore | JSON хранилище | put(), get(), delete() |
| DictStore | Словарное хранилище | store, find() | |
| Сеть | UrlRequest | HTTP запросы | url, on_success, on_error |
| Утилиты | Factory | Создание объектов | register(), unregister() |
| Builder | KV конструктор | load_file(), load_string() | |
| Logger | Логирование | info(), warning(), error() | |
| Свойства | StringProperty | Строковое свойство | allownone, defaultvalue |
| NumericProperty | Числовое свойство | min, max, errorvalue | |
| BooleanProperty | Логическое свойство | defaultvalue | |
| ObjectProperty | Объектное свойство | allownone, baseclass | |
| ListProperty | Список | defaultvalue | |
| DictProperty | Словарь | defaultvalue | |
| Платформы | platform | Определение платформы | android, ios, win, linux, macosx |
| Метрики | dp | Независимые пиксели | - |
| sp | Масштабируемые пиксели | - | |
| mm, cm, inch | Физические единицы | - |
Практические примеры и проекты
Создание калькулятора
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class CalculatorApp(App):
def build(self):
main_layout = GridLayout(rows=2)
# Дисплей
self.solution = TextInput(
multiline=False, readonly=True, halign="right"
)
main_layout.add_widget(self.solution)
# Кнопки
buttons = [
['7', '8', '9', '/'],
['4', '5', '6', '*'],
['1', '2', '3', '-'],
['.', '0', 'C', '+'],
['=']
]
buttons_layout = GridLayout(cols=4)
for row in buttons:
for button in row:
btn = Button(text=button)
btn.bind(on_press=self.on_button_press)
buttons_layout.add_widget(btn)
main_layout.add_widget(buttons_layout)
return main_layout
def on_button_press(self, instance):
current = self.solution.text
button_text = instance.text
if button_text == 'C':
self.solution.text = ''
elif button_text == '=':
try:
self.solution.text = str(eval(current))
except:
self.solution.text = 'Ошибка'
else:
self.solution.text = current + button_text
CalculatorApp().run()
Менеджер задач
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
class TaskManager(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.orientation = 'vertical'
self.tasks = []
# Поле ввода новой задачи
input_layout = BoxLayout(size_hint_y=None, height=50)
self.task_input = TextInput(hint_text='Введите новую задачу')
add_button = Button(text='Добавить', size_hint_x=None, width=100)
add_button.bind(on_press=self.add_task)
input_layout.add_widget(self.task_input)
input_layout.add_widget(add_button)
self.add_widget(input_layout)
# Список задач
self.task_list = BoxLayout(orientation='vertical', size_hint_y=None)
self.task_list.bind(minimum_height=self.task_list.setter('height'))
scroll = ScrollView()
scroll.add_widget(self.task_list)
self.add_widget(scroll)
def add_task(self, instance):
task_text = self.task_input.text.strip()
if task_text:
task_layout = BoxLayout(size_hint_y=None, height=40)
task_label = Label(text=task_text, text_size=(None, None))
delete_button = Button(text='Удалить', size_hint_x=None, width=100)
delete_button.bind(on_press=lambda x: self.delete_task(task_layout))
task_layout.add_widget(task_label)
task_layout.add_widget(delete_button)
self.task_list.add_widget(task_layout)
self.task_input.text = ''
def delete_task(self, task_layout):
self.task_list.remove_widget(task_layout)
class TaskApp(App):
def build(self):
return TaskManager()
TaskApp().run()
Часто задаваемые вопросы
Как оптимизировать производительность Kivy-приложения?
Для оптимизации производительности следует:
- Использовать Canvas инструкции вместо множества виджетов для статичной графики
- Минимизировать количество виджетов в дереве
- Применять RecycleView для больших списков данных
- Оптимизировать изображения (использовать подходящие форматы и размеры)
- Избегать частых обновлений интерфейса в циклах
Можно ли использовать Kivy для создания игр?
Да, Kivy отлично подходит для создания 2D игр благодаря:
- Встроенной поддержке анимаций
- Эффективному рендерингу через OpenGL
- Поддержке мультитача и жестов
- Возможности работы со звуком и музыкой
- Кроссплатформенности
Как обеспечить адаптивность интерфейса под разные экраны?
Для создания адаптивного интерфейса используйте:
- size_hint для относительных размеров
- dp/sp единицы измерения вместо пикселей
- Условную логику в KV файлах на основе размеров экрана
- Разные layouts для разных ориентаций
- Тестирование на различных устройствах
Как работать с базами данных в Kivy?
Kivy поддерживает различные способы работы с данными:
- SQLite через встроенный модуль sqlite3
- JsonStore для простого хранения настроек
- Интеграция с ORM (SQLAlchemy, Peewee)
- Работа с облачными базами данных через REST API
Поддерживает ли Kivy уведомления?
Для работы с уведомлениями используйте библиотеку Plyer:
from plyer import notification
notification.notify(
title='Заголовок уведомления',
message='Текст уведомления',
app_name='My App',
app_icon=None,
timeout=10,
)
Заключение
Kivy представляет собой мощный и гибкий инструмент для создания кроссплатформенных приложений на Python. Фреймворк особенно привлекателен для разработчиков, которые хотят создавать приложения для мобильных устройств, не изучая специфичные для платформ языки программирования.
Основные преимущества Kivy включают единую кодовую базу для всех платформ, мощную систему виджетов, встроенную поддержку мультитача и современный подход к созданию пользовательских интерфейсов. KV-язык разметки позволяет четко разделить логику приложения и его визуальное представление, что значительно упрощает разработку и поддержку кода.
Благодаря активному сообществу разработчиков, обширной документации и множеству примеров, Kivy остается одним из лучших решений для Python-разработчиков, стремящихся создавать современные, адаптивные и функциональные приложения для широкого спектра устройств и платформ.
Настоящее и будущее развития ИИ: классической математики уже недостаточно
Эксперты предупредили о рисках фейковой благотворительности с помощью ИИ
В России разработали универсального ИИ-агента для роботов и индустриальных процессов