Приветствую всех любителей и знатоков языка программирования Python!

Сегодня продолжим разбираться с темой анимаций в кроссплатформенном фреймворке для с поддержкой мультитач — Kivy в связке с библиотекой компонентов Google Material DesignKivyMD. В прошлой статье мы уже разбирали пример тестового приложения на Python/Kivy/KivyMD, в этой — пройдемся по теме анимаций более подробно. В конце статьи я приведу ссылку на репозиторий проекта, в котором вы сможете скачать и сами пощупать, демонстрационное Kivy/KivyMD приложение. Как и предыдущая, эта статья будет содержать не маленькое количество GIF анимаций и видео, а поэтому наливайте кофе и погнали!

Kivy работает на Linux, Windows, OS X, Android, iOS и Raspberry Pi. Вы можете запустить один и тот же код на всех поддерживаемых платформах без внесения дополнительных изменений в кодовую базу. Kivy поддерживает большое количество устройств ввода, включая WM_Touch, WM_Pen, Mac OS X Trackpad и Magic Mouse, Mtdev, Linux Kernel HID, TUIO и так же как и Flutter, не задействует нативные элементы управления. Все его виджеты настраиваются. Это значит, что приложения Kivy будут выглядеть одинаково на всех платформах. Но благодаря тому, что виджеты Kivy могут быть кастомизированы как угодно, вы можете создавать свои собственные виджеты. Например, так появилась библиотека KivyMD. Прежде чем продолжить, давайте посмотрим небольшой обзор возможностей Kivy:

Демонстрационные ролики Kivy приложений






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

from kivy.animation import Animation
from kivy.lang import Builder

from kivymd.app import MDApp


KV = """
<CommonLabel@MDLabel>
    opacity: 0
    adaptive_height: True
    halign: "center"
    y: -self.height


MDScreen:
    on_touch_down: app.start_animation()

    CommonLabel:
        id: lbl_1
        font_size: "32sp"
        text: "M A R S"

    CommonLabel:
        id: lbl_2
        font_size: "12sp"
        text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
"""


class TestAnimation(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def start_animation(self):
        lbl_1 = self.root.ids.lbl_1
        lbl_2 = self.root.ids.lbl_2

        Animation(
            opacity=1, y=lbl_1.height * 2, d=0.9, t="in_out_back"
        ).start(lbl_1)
        Animation(
            opacity=1, y=lbl_2.height + ids.lbl_1.height, d=1, t="in_out_back"
        ).start(lbl_2)


TestAnimation().run()

Это уже готовое приложение. Мы будем его лишь слегка редактировать. Правило CommonLabel в KV строке аналогично созданию класса в Python коде. Сравните:


Код в Kivy Language всегда короче и читабельнее. Поэтому в Python коде у нас будет только логика. Мы создали две метки с общими свойствами, описанными в правиле CommonLabel: прозрачность (opacity), размер текстуры метки (adaptive_height), горизонтальное выравнивание (halign), положение по оси Y (y ) и дали этим меткам id-шники (lbl_1, lbl_2), чтобы иметь возможность обращаться к свойствам объектов меток и манипулировать ими из Python кода. Далее мы привязали к событию on_touch_down (сработает при прикосновении к экрану в любом месте) вызов метода start_animation, в котором будем анимировать наши две метки.

Animation


Для анимарования объектов в Kivy используется класс Animation. Использовать его очень просто: при инициализации класса Animation вы должны передать в качестве аргументов имена свойств с целевыми значениями, которые будут достигнуты в конце анимации. Например:

    def start_animation(self):
        # Получаем объекты меток из KV разметки
        lbl_1 = self.root.ids.lbl_1
        lbl_2 = self.root.ids.lbl_2
        # Анимация первой метки
        Animation(
            opacity=1,  # анимация прозрачности до значения 1
            y=lbl_1.height * 2,  # анимация положения виджета по оси Y
            d=0.9,  # время выполнения анимация
            t="in_out_back"  # тип анимации
        ).start(lbl_1)  # в метод start передаем объект, который нужно анимаровать
        # Анимация второй метки
        Animation(
            opacity=1, y=lbl_2.height + lbl_1.height, d=1, t="in_out_back"
        ).start(lbl_2)

На нижеследующей анимации я продемонстрировал результат простейшей анимации, которую мы создали, с разными типами анимирования:

  1. in_out_back
  2. out_elastic
  3. linear


Давайте немного усложним задачу и попробуем анимировать вращение меток на плоскости. Для этого будем использовать матричные манипуляции (PushMatrix, PopMatrix, Rotate, Translate, Scale). Добавим к общей метке инструкции canvas:

<CommonLabel@MDLabel>
    angle: 180  # значение вращения
    [...]

    canvas.before:
        PushMatrix
        Rotate:
            angle: self.angle
            origin: self.center
    canvas.after:
        PopMatrix

А в Python коде в класс Animation передадим новое свойство angle для анимации:

    def start_animation(self):
        lbl_1 = self.root.ids.lbl_1
        lbl_2 = self.root.ids.lbl_2

        Animation(angle=0, [...]).start(lbl_1)
        Animation(angle=0, [...]).start(lbl_2)

Результат:

Добавим анимирование масштаба меток:

<CommonLabel@MDLabel>
    scale: 5  # значение масшбирования
    [...]

    canvas.before:
        PushMatrix
        [...]
        Scale:
            # масштабирование по трем осям
            x: self.scale
            y: self.scale
            z: self.scale
            origin: self.center
    canvas.after:
        PopMatrix

В Python коде в класс Animation передадим новое свойство scale для анимации:

    def start_animation(self):
        lbl_1 = self.root.ids.lbl_1
        lbl_2 = self.root.ids.lbl_2

        Animation(scale=1, [...]).start(lbl_1)
        Animation(scale=1, [...]).start(lbl_2)

Результат:

Класс Animation имеет ряд событий для отслеживания процесса анимации: on_start, on_progress, on_complete. Рассмотрим последний. on_complete вызывается в момент завершения процесса анимации. Привяжем это событие к методу complete_animation, который мы сейчас создадим:

[...]


class TestAnimation(MDApp):
    [...]

    def complete_animation(self, animation, animated_instance):
        """
        :type animation: <kivy.animation.Animation object>
        :type animated_instance: <WeakProxy to <kivy.factory.CommonLabel object>>
        """

        # Анимируем масштаб и цвет первой метки.
        Animation(scale=1.4, d=1, t="in_out_back").start(animated_instance)
        Animation(color=(1, 0, 1, 1), d=1).start(animated_instance)

Привязываем событие:

    def start_animation(self):
        [...]

        animation = Animation(
            angle=0, scale=1, opacity=1, y=lbl_1.height * 2, d=0.9, t="in_out_back"
        )
        animation.bind(on_complete=self.complete_animation)
        animation.start(lbl_1)

        [....]

Результат:

На этом пока все. Просили:

Ниже прикрепляю превью Kivy/KivyMD проекта и ссылку на репозиторий, где можно скачать APK и пощупать:

> Репозиторий

APK можно найти в директории репозитория — StarTest/bin