Вступление
Всем доброго дня! В предыдущей статье KivyMD 2.0.0 — путеводитель по Material Design для Kivy:
- Я рассказал о библиотеке KivyMD 2.0.0 и её установке;
- Сделал обзор UI-виджетов из папки
examples
.
Предыдущая моя статья была обзорной и познакомила с основными возможностями KivyMD 2.0.0, , а также с виджетами Material Design для Kivy.
Сегодня же я перехожу от теории к практике. Начну с экрана «Таймеры», в который пользователь попадает сразу после запуска приложения Kawai.Focus
. Моя цель — начать преображение внешнего вида приложения, сделав его более красивым и удобным.
Заваривайте чай, доставайте вкусняшки — пора “выращивать красивые помидоры в Material Design”! 🍅
Экран "Таймеры"
Я начну с изменения дизайна экрана «Таймеры», в который пользователь попадает сразу после запуска приложения Kawai.Focus
..
Старый дизайн экрана «Таймеры»:

Что не так с этим дизайном?
- Нет полноценного меню — только одна кнопка внизу;
- Список таймеров представлен простыми кнопками;
- Цвета и оформление выглядят блекло и непривлекательно.
Подбор образцов
Перед началом работы над новым дизайном экрана мне нужно определиться, какой внешний вид приложения я хочу получить. Также важно понять, какие образцы из examples
могут послужить основой для экрана «Таймеры». Возможно, потребуется добавить дополнительные кнопки с функционалом.
Первое, что я хочу сделать, — это найти пример для списка данных. К счастью, для этого я уже написал отдельную статью-путеводитель.
В качестве основы я беру образец expansionpanel.py
для списка таймеров. Он использует сворачиваемую и разворачиваемую панель, которая удобно скрывает описание таймера и его кнопки. В свёрнутом виде остаётся только название, что делает отображение списка более компактным. При желании сюда можно встроить кнопки для CRUD-операций — например, редактирование и удаление. Это позволит гибко управлять таймерами прямо из экрана «Таймеры». Меню я планирую сделать простым, в выпадающем стиле.
Образец expansionpanel.py
:

Здесь хочу немного рассказать о направленности моего приложения: для каких устройств и задач я его разрабатываю.
Приложение ориентировано в первую очередь на людей, которые работают за компьютером, ноутбуком или планшетом. У них рабочее пространство — это широкий экран, и поэтому я использую элементы дизайна, характерные для десктопных приложений. Например, выпадающее меню здесь особенно удобно.
А что насчёт смартфонов? Смартфон — устройство небольшое, где удобнее включать режим «Не беспокоить» или временно отключать интернет. Возможно, в будущем я создам дополнительное мобильное приложение, которое будет синхронизироваться через интернет с десктопной версией и управлять такими функциями.
timers_screen.kv
Настало время адаптировать образец expansionpanel.py
для использования на экране «Таймеры».
В примере kv
-файл хранится прямо в строке Python, а не в отдельном файле. Это удобно для демонстрации, когда можно сразу увидеть и код, и kv
, но при этом сильно захламляет исходник. Поэтому я предпочитаю выносить kv
в отдельные файлы.
Обновлённый timers_screen.kv
:
#:kivy 2.3.1
# Кастомная панель для каждого таймера
<ExpansionPanelItem>:
MDExpansionPanelHeader:
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
MDListItemSupportingText:
text: root.title
TrailingPressedIconButton:
id: chevron
icon: "chevron-right"
on_release: app.tap_expansion_chevron(root, chevron)
MDExpansionPanelContent:
orientation: "vertical"
padding: "12dp", 0, "12dp", "12dp"
md_bg_color: self.theme_cls.surfaceContainerLowColor
adaptive_height: True
MDLabel:
text: "Информация о таймере"
adaptive_height: True
padding_x: "16dp"
padding_y: "12dp"
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
on_release: None
MDListItemLeadingIcon:
icon: "information-outline"
MDListItemHeadlineText:
text: root.info
MDBoxLayout:
padding: [8, 8, 0, 0]
size_hint_y: None
height: self.minimum_height
MDButton:
style: "outlined"
size_hint_x: 1
MDButtonText:
text: "Открыть"
# Основной экран
<TimersScreen>:
md_bg_color: self.theme_cls.backgroundColor
MDIconButton:
on_release: app.open_menu(self)
pos_hint: {"top": .98}
x: "12dp"
icon: "menu"
ScrollView:
size_hint_x: .9
pos_hint: {"center_x": .5, "center_y": .5}
do_scroll_x: False
do_scroll_y: True
MDList:
id: container
spacing: "8dp"
padding: [56, 8, 56, 0] # [слева, сверху, справа, снизу]
1. Компонент ExpansionPanelItem
:
- Служит обёрткой для каждого таймера, предоставляя функционал раскрывающейся панели;
- Состоит из двух основных частей:
MDExpansionPanelHeader
— заголовок панели:MDListItem
с кастомным цветом фона (surfaceContainerLowColor
);MDListItemSupportingText
показывает название таймера (root.title
);- Кнопка-стрелка (
TrailingPressedIconButton
) для разворачивания/сворачивания панели. Обработчик события —app.tap_expansion_chevron(root, chevron)
.
MDExpansionPanelContent
— содержимое панели:- Ориентация вертикальная, внутренние отступы
"12dp"
; MDLabel
с текстом"Информация о таймере"
;- Дополнительный
MDListItem
:- С иконкой
information-outline
; - С текстом
root.info
; - Без ripple-эффекта, чтобы элемент выглядел как статическая информация.
- С иконкой
MDBoxLayout
с кнопкойMDButton
(стиль"outlined"
) и текстом"Открыть"
— позволяет выполнить дополнительное действие с таймером.
- Ориентация вертикальная, внутренние отступы
2. Основной экран TimersScreen
:
- Устанавливает фон через
self.theme_cls.backgroundColor
; - Верхний левый угол занимает
MDIconButton
с иконкой меню (icon: "menu"
), которое вызываетapp.open_menu(self)
; - Содержимое экрана помещено в
ScrollView
для вертикальной прокрутки:- Пропорции и позиционирование: ширина 90%, центрирование по центру;
- Внутри —
MDList
(id: container
) с отступами[56, 8, 56, 0]
и расстоянием между элементами"8dp"
; - Список служит контейнером для всех панелей таймеров.
3. Функциональная идея:
- Каждая панель (
ExpansionPanelItem
) представляет отдельный таймер с краткой и расширенной информацией; - Пользователь видит:
- Название таймера в заголовке;
- Подробности при раскрытии панели;
- Кнопку для выполнения действий (например, открытие таймера или его редактирование).
- Такая структура позволяет создать удобный и визуально понятный интерфейс для управления множеством таймеров.
4. Визуальная логика:
- Заголовки и контент панелей используют согласованную цветовую схему (
theme_cls.surfaceContainerLowColor
) для единого дизайна; - Элементы списка и кнопки оформлены с учётом Material Design, обеспечивая современный и аккуратный вид.
Сейчас я делаю упор на дизайн, поэтому кнопки пока не подключаю. Когда дойду до реализации переходов на другие экраны — тогда займусь обработкой нажатий.
cruds.py
Мне нужно немного поправить CRUD-операцию для получения списка со словарями таймеров. Для новой логики необходимо выделять поле title
отдельно от основной строки с информацией о таймере.
Обновлённый код функции list_timers()
:
@crud_error_guard
def list_timers() -> list[dict[str, int | str]]:
"""Функция для получения списка таймеров"""
# Другой код
return [
{
'timer_id': timer.id,
'title': timer.title,
'info': (
f'Помидоров: {timer.count_pomodoro}, '
f'Размер помидора: {timer.pomodoro_time}'
)
}
for timer in timers
]
Теперь название будет храниться по ключу title
, а описание — по ключу info
.
timers_screen.py
Теперь я займусь обновлением основной логики экрана «Таймеры», которую нужно переделать для работы с библиотекой kivymd
.
Импорты:
from kivy.properties import StringProperty, NumericProperty
from kivymd.uix.screen import MDScreen
from kivymd.uix.expansionpanel import MDExpansionPanel
from kawai_focus.utils.utils import calculate_time, gen_types_timers
from kawai_focus.database.cruds import get_timer, list_timers
from kawai_focus.main import Logger
Разбор обновлённых импортов:
from kivy.properties import StringProperty, NumericProperty
:- Импорт свойств (properties) для Kivy, используемых в виджетах:
StringProperty
— для строковых значений (например, название таймера);NumericProperty
— для числовых значений (например, длительность таймера).
- Эти свойства позволяют автоматически отслеживать изменения и обновлять интерфейс.
- Импорт свойств (properties) для Kivy, используемых в виджетах:
from kivymd.uix.screen import MDScreen
:- Импорт класса экрана с Material Design стилем;
- Используется как базовый виджет для создания отдельных экранов приложения (например,
TimersScreen
).
from kivymd.uix.expansionpanel import MDExpansionPanel
:- Импорт раскрывающейся панели Material Design;
- Служит для создания элементов с заголовком и скрытым содержимым, которые можно разворачивать/сворачивать.
Класс ExpansionPanelItem
:
class ExpansionPanelItem(MDExpansionPanel):
"""Кастомный элемент панели с данными таймера"""
timer_id = NumericProperty()
title = StringProperty()
info = StringProperty()
Разбор кода класса:
class ExpansionPanelItem(MDExpansionPanel)
:- Создаёт кастомный элемент панели для таймера;
- Наследует функционал
MDExpansionPanel
(Material Design панель с заголовком и скрытым содержимым).
- Свойства класса:
timer_id = NumericProperty()
— уникальный идентификатор таймера;title = StringProperty()
— название таймера, отображается в заголовке панели;info = StringProperty()
— дополнительная информация о таймере, показывается при раскрытии панели.
Назначение класса:
- Этот класс инкапсулирует все данные одного таймера и его визуальное представление в виде панели;
- Позволяет создавать список таймеров, где каждый элемент имеет заголовок, описание и возможность раскрытия для деталей.
Обновлённый класс TimersScreen
:
class TimersScreen(MDScreen):
"""Экран таймеров"""
def on_enter(self, *args) -> None:
"""Загружает список таймеров при входе на экран"""
self.load_timers()
def load_timers(self) -> None:
"""Загружает все таймеры и добавляет их в контейнер"""
self.ids.container.clear_widgets()
all_timers = list_timers()
for timer_data in all_timers:
panel = ExpansionPanelItem(
timer_id=timer_data.get('timer_id'),
title=timer_data.get('title'),
info=timer_data.get('info'),
)
self.ids.container.add_widget(panel)
def switch_timer(self, instance) -> None:
"""Метод для кнопки переключения на выбранный таймер"""
timer = get_timer(timer_id=instance.timer_id)
if not timer:
Logger.warning(f'Таймер с ID {instance.timer_id} не найден!')
return
screen_timer = self.manager.get_screen('timer_screen')
screen_timer.timer = timer
time_calc = calculate_time(mm_user=timer.pomodoro_time)
screen_timer.timer_start_time = time_calc
screen_timer.ids.time_label.text = time_calc
screen_timer.ids.title_label.text = timer.title
screen_timer.source_timer_names = gen_types_timers(count_pomodoro=timer.count_pomodoro)
self.manager.state_machine = screen_timer.source_timer_names.copy()
self.manager.current = 'timer_screen'
Разбор обновлённого кода:
- Функция
on_enter
:- Назначение: вызывается автоматически при входе на экран (
MDScreen
); - Действие: запускает метод
load_timers()
, чтобы отобразить актуальный список таймеров; - Эффект для пользователя: каждый раз, когда пользователь открывает экран таймеров, список обновляется и отражает все текущие таймеры.
- Назначение: вызывается автоматически при входе на экран (
- Функция
load_timers
:- Назначение: загружает данные всех таймеров и создаёт для каждого визуальный элемент (
ExpansionPanelItem
). - Этапы работы:
- Очищает контейнер
MDList
от предыдущих виджетов (clear_widgets
); - Получает список таймеров через функцию
list_timers()
; - Для каждого таймера создаёт панель с уникальным
timer_id
, названием (title
) и информацией (info
); - Добавляет панель в
container
для отображения на экране.
- Очищает контейнер
- Эффект для пользователя: динамический список таймеров, который можно раскрывать, просматривать детали и взаимодействовать с каждым элементом.
- Назначение: загружает данные всех таймеров и создаёт для каждого визуальный элемент (
- Код проверки таймера в
switch_timer
:- Назначение: проверяет, существует ли таймер с переданным
timer_id
. - Что делает код:
- Если таймер не найден, выводит предупреждение в лог (
Logger.warning
); - Завершает выполнение функции (
return
), чтобы предотвратить ошибки при попытке работать с несуществующим таймером.
- Если таймер не найден, выводит предупреждение в лог (
- Назначение: проверяет, существует ли таймер с переданным
- Зачем это нужно: предотвращает падение приложения и информирует разработчика о проблеме с данными.
Теперь экран «Таймеры» готов к работе с новым дизайном.
Переключение темы
Тема в приложении — это набор визуальных стилей и настроек оформления, который определяет внешний вид интерфейса: цвета, шрифты, иконки и фоновые элементы. Она позволяет менять дизайн приложения целиком, чтобы адаптировать его под предпочтения пользователя или разные режимы (например, светлый и тёмный).
Разработчики KivyMD 2.0.0 уже создали готовый механизм для переключения тем, который остаётся лишь встроить в приложение и использовать.
Образец navigation_rail.py
(переключение тем):

Возможности переключения тем:
Set palette
(Установить палитру) — позволяет изменить основную цветовую схему приложения. В KivyMD вы можете выбрать основной цвет (например, "Orange", "Red", "Blue") из предопределенного набора, и все основные компоненты интерфейса будут окрашены в его оттенки. Это управляется через свойствоprimary_palette
;Switch theme style
(Переключить стиль темы) — переключает приложение между светлым и темным режимами (Light
иDark
). При смене стиля меняются цвета фона, текста и других элементов для соответствия выбранному режиму. KivyMD также поддерживает анимацию этого перехода;Switch scheme type
(Переключить тип схемы) — относится к динамическим темам Material Design 3, которые позволяют генерировать цветовую схему на основе, например, обоев рабочего стола (на Android 12+). KivyMD поддерживает различные типы динамических схем, такие какTONAL_SPOT
,VIBRANT
,EXPRESSIVE
и другие, которые влияют на то, как именно генерируются цвета темы;Disabled widgets
(Отключенные виджеты) — этот пункт, не меняет саму тему, а является демонстрационной опцией. Он показывает, как выглядят виджеты (кнопки, переключатели и т.д.), когда они находятся в неактивном (отключенном) состоянии при текущих настройках темы. Их внешний вид, например, яркость и цвет, зависит от выбранной палитры и стиля темы.
menu_app.py
Я немного адаптирую код common_app.py из exsamples
под свои нужды. В частности, я переведу меню на русский, добавлю пункт-заглушку в качестве заготовки для создания нового таймера и слегка расширю код докстрингами и аннотациями.
Импорты:
from kivy.utils import hex_colormap
from kivy.uix.widget import Widget
from materialyoucolor.utils.platform_utils import SCHEMES
from kivymd.uix.menu import MDDropdownMenu
Разбор импортов:
from kivy.utils import hex_colormap
:- Утилита для работы с цветами в формате HEX;
- Позволяет конвертировать строковые HEX-коды в цветовые значения Kivy.
from kivy.uix.widget import Widget
:- Базовый класс для всех визуальных элементов Kivy;
- Используется для создания кастомных виджетов и контейнеров.
from materialyoucolor.utils.platform_utils import SCHEMES
:- Импорт словаря или константы с цветовыми схемами Material You;
- Позволяет выбирать готовые палитры цветов для интерфейса.
from kivymd.uix.menu import MDDropdownMenu
:- Виджет выпадающего меню Material Design;
- Используется для создания меню с элементами выбора, которое появляется при нажатии.
Класс MenuApp
:
class MenuApp:
"""Класс для меню приложения"""
menu: MDDropdownMenu = None
def open_menu(self, menu_button) -> None:
"""Открывает выпадающее меню"""
menu_items = []
for item, method in {
'Цвет темы': lambda: self.set_palette(),
'Стиль темы': lambda: self.switch_theme(),
'Тип схемы': lambda: self.set_scheme_type(),
'Новый таймер': None
}.items():
menu_items.append(
{
'text': item,
'on_release': method,
}
)
self.menu = MDDropdownMenu(
caller=menu_button,
items=menu_items,
)
self.menu.open()
def switch_palette(self, selected_palette: str) -> None:
"""Переключает основной цвет темы"""
self.theme_cls.primary_palette = selected_palette
def switch_theme(self) -> None:
"""Переключает светлую/тёмную тему"""
self.theme_cls.switch_theme()
def set_palette(self) -> None:
"""Формирует и открывает меню выбора палитры"""
instance_from_menu = self.get_instance_from_menu('Set palette')
available_palettes = [
name_color.capitalize() for name_color in hex_colormap.keys()
]
menu_items = []
for name_palette in available_palettes:
menu_items.append(
{
'text': name_palette,
'on_release': lambda x=name_palette: self.switch_palette(x),
}
)
MDDropdownMenu(
caller=instance_from_menu,
items=menu_items,
).open()
def set_scheme_type(self) -> None:
"""Формирует и открывает меню выбора типа цветовой схемы"""
instance_from_menu = self.get_instance_from_menu("Switch scheme type")
menu_items = []
for scheme_name in SCHEMES.keys():
menu_items.append(
{
'text': scheme_name,
'on_release': lambda x=scheme_name: self.update_scheme_name(x),
}
)
MDDropdownMenu(
caller=instance_from_menu,
items=menu_items,
).open()
def update_scheme_name(self, scheme_name: str) -> None:
"""Обновляет тип цветовой схемы"""
self.theme_cls.dynamic_scheme_name = scheme_name
def get_instance_from_menu(self, name_item: str) -> Widget:
"""Возвращает экземпляр элемента меню по его названию"""
index = 0
rv = self.menu.ids.md_menu
opts = rv.layout_manager.view_opts
datas = rv.data[0]
for data in rv.data:
if data.get('text') name_item:
index = rv.data.index(data)
break
instance = rv.view_adapter.get_view(
index, datas, opts[index].get('viewclass')
)
return instance
def disabled_widgets(self) -> None:
"""Переключает активность виджетов (блокирует/разблокирует)"""
for widget in self.root.ids.widget_box.children:
widget.disabled = not widget.disabled
for widget in self.root.ids.custom_widget_box.children:
widget.disabled = not widget.disabled
Краткий разбор кода:
open_menu(menu_button)
— формирует и открывает главное выпадающее меню с пунктами: выбор цвета темы, стиля, типа схемы, новый таймер;switch_palette(selected_palette)
— меняет основной цвет темы (primary_palette
);switch_theme()
— переключает светлую/тёмную тему приложения;set_palette()
— создаёт и открывает меню выбора палитры, связывая пункты сswitch_palette
;set_scheme_type()
— создаёт и открывает меню выбора типа цветовой схемы, связывая пункты сupdate_scheme_name
;update_scheme_name(scheme_name)
— обновляет выбранный тип цветовой схемы (dynamic_scheme_name
);get_instance_from_menu(name_item)
— возвращает виджет меню по его названию для последующей работы с ним;disabled_widgets()
— переключает активность виджетов (disabled
) в контейнерахwidget_box
иcustom_widget_box
.
main.py
Настало время собрать приложение воедино в главном файле.
Обновлённые импорты:
import kivy
kivy.require('2.3.1')
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.metrics import dp
from kivy.uix.behaviors import ButtonBehavior
from kivy.logger import Logger
import logging
from kivymd.app import MDApp
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.list import MDListItemTrailingIcon
from kawai_focus.menu_app import MenuApp
from kawai_focus.screens.timers_screen import TimersScreen
Разбор новых импортов:
from kivy.animation import Animation
:- Позволяет создавать анимации для виджетов (например, плавное изменение позиции, размера, цвета).
from kivy.metrics import dp
:- Функция для перевода единиц измерения в "density-independent pixels" (независимые от плотности экрана).
from kivy.uix.behaviors import ButtonBehavior
:- Поведение, которое превращает любой виджет в кнопку с возможностью обработки нажатий.
from kivymd.app import MDApp
:- Базовый класс приложения KivyMD с поддержкой Material Design.
from kivymd.uix.screenmanager import MDScreenManager
:- Менеджер экранов с Material Design для переключения между экранами (
MDScreen
).
- Менеджер экранов с Material Design для переключения между экранами (
from kivymd.uix.expansionpanel import MDExpansionPanel
:- Виджет раскрывающейся панели Material Design (заголовок + скрытое содержимое).
from kivymd.uix.behaviors import RotateBehavior
:- Поведение для виджетов, позволяющее их вращать (например, анимировать стрелку панели).
from kivymd.uix.list import MDListItemTrailingIcon
:- Элемент списка Material Design с текстом и иконкой справа (например, стрелка или кнопка действия).
Класс TrailingPressedIconButton
:
class TrailingPressedIconButton(
ButtonBehavior, RotateBehavior, MDListItemTrailingIcon
):
"""Кнопка-иконка в конце элемента списка с поддержкой анимации"""
...
Разбор кода:
- Наследование:
ButtonBehavior
— превращает виджет в кнопку, позволяя реагировать на нажатия;RotateBehavior
— добавляет возможность вращения виджета (анимация поворота);MDListItemTrailingIcon
— стандартная иконка справа в элементе списка Material Design.
- Назначение класса:
- Создаёт кнопку-иконку в конце элемента списка, которая может быть нажата и анимирована вращением;
- Используется, например, как стрелка для раскрытия
MDExpansionPanel
с плавной анимацией.
- Особенности:
- Объединяет функционал кликабельности, анимации и визуального отображения иконки в одном виджете.
Обновлённый класс KawaiFocusApp
:
class KawaiFocusApp(MDApp, MenuApp):
"""Главный класс приложения"""
def build(self) -> MDScreenManager:
"""Создаёт и возвращает менеджер экранов приложения"""
self.theme_cls.theme_style = 'Dark'
# Загрузка kv файла
Builder.load_file('kv/timers_screen.kv')
self.screen_manager = MDScreenManager()
self.timers_screen = TimersScreen(name='timers_screen')
self.screen_manager.add_widget(self.timers_screen)
return self.screen_manager
def tap_expansion_chevron(
self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton
) -> None:
"""Анимация и переключение состояния раскрытия панели"""
Animation(
padding=(
[0, dp(12), 0, dp(12)] if not panel.is_open else [0, 0, 0, 0]
),
d=0.2,
).start(panel)
panel.open() if not panel.is_open else panel.close()
(
panel.set_chevron_down(chevron)
if not panel.is_open
else panel.set_chevron_up(chevron)
)
Разбор обновлённого кода:
KawaiFocusApp(MDApp, MenuApp)
— объединяет функционал KivyMD приложения и кастомного меню (MenuApp
);MDApp
— базовый класс приложения с поддержкой Material Design;MenuApp
— добавляет функционал меню: выбор палитры, темы, схемы, блокировку виджетов;self.theme_cls.theme_style = 'Dark'
— устанавливает тёмную тему приложения;Builder.load_file(...)
— загружает внешний.kv
файл с разметкой интерфейса;self.screen_manager = MDScreenManager()
— менеджер экранов с Material Design анимациями, отличается от стандартногоScreenManager
плавностью переходов и стилем;- Добавление экрана через
add_widget
— позволяет переключаться на экран таймеров черезscreen_manager.current
; tap_expansion_chevron
— обрабатывает нажатие на стрелку панели:- анимирует отступы панели;
- переключает состояние панели (открыта/закрыта);
- вращает стрелку (
chevron
) в зависимости от состояния панели.
Я временно убрал все лишние экраны, чтобы ничего не мешало и не путало меня. Также обратите внимание, что класс KawaiFocusApp
наследует меню MenuApp
как часть приложения, которое не является отдельным экраном.
Запуск с новым дизайном
Настало время посмотреть, как выглядит новый дизайн экрана «Таймеры» и оценить его анимации.
Запускаю приложение в terminal:
poetry run kawai-focus
Первое, что я вижу — это компактный список таймеров, каждый из которых можно развернуть для подробного просмотра.
Разворачиваю «Таймер 1»:

Теперь отображается подробная информация о «Таймере 1» и кнопка «Открыть», которая отвечает за переход к таймеру. Хочу отметить, что такая структура удобна для расширения. Сюда легко добавить кнопки «Редактировать» и «Удалить», что повысит удобство и скорость работы с приложением.
Нажимаю на выпадающее меню:

Все пункты меню я переименовал на русский язык для удобства пользователя.
Нажму на пункт «Цвет темы»:

Появляется список цветов, который можно пролистывать. Единственное — в этом меню нет видимой боковой прокрутки и возможности выделять мышкой, из-за чего управление выглядит немного топорным. Однако я решил сохранить механику работы такой, какой её сделали разработчики.

Прокручиваю меню вниз и выбираю цвет Tan, представляющий собой светло-коричневый оттенок. Все цвета темы сразу же изменяются. Мне нравится, что разработчики KivyMD 2.0.0 предоставляют такие широкие возможности для настройки внешнего вида приложения.
В будущем я добавлю сохранение выбранных настроек темы, чтобы после перезапуска приложения они оставались такими же, какими их задал пользователь. Сейчас же тема сбрасывается при каждом запуске.

Выбираю «Стиль темы»:

Весь экран приложения сразу становится светлым. Здесь всё просто: одно нажатие — тёмная тема, второе — светлая.

Выбераю пункт «Тип схемы»:

Из списка схем выбираю «MONOCHROME», то есть монохромную цветовую палитру.

Переключаю обратно на тёмную тему:

Теперь я решил проверить, как приложение выглядит в маленьком окне, а также работу полосы прокрутки. Для этого уменьшаю окно приложения и раскрываю все таймеры. Так как содержимое не помещается на экран, появляется возможность прокручивать его вверх и вниз.

Прокручиваю вниз:

Как пользователь могу сказать, что работать с приложением стало гораздо приятнее.
Через картинки невозможно передать плавность работы и все эффекты анимации, поэтому я записал наглядный видеоролик.
Видео запуска:
Анонс на следующие статьи
Сегодня был обновлён дизайн экрана «Таймеры», и я считаю, что он получился гораздо лучше и привлекательнее, чем раньше. Будет интересно услышать ваше мнение в комментариях.
Моя следующая статья выйдет 23.10.2025. В ней я продолжу работать над красивым Material Design — на этот раз над экраном «Таймер». Также я подключу кнопку для перехода на него.
Если у вас есть мысли о том, как можно улучшить проект, пишите в комментариях — с удовольствием ознакомлюсь с вашими предложениями!
Читайте продолжение — не пропустите!
Заключение
- Обновлён дизайн для экрана "Таймеры";
- Добавлены темы для приложения.
Ссылки к статье
- Мои статьи Arduinum628 на Код на салфетке;
- Репозиторий проекта Kawai.Focus.
Комментарии
Оставить комментарийВойдите, чтобы оставить комментарий.
Комментариев пока нет.