素材デザイン。Kivyでアニメーションを作成する



Pythonプログラミング言語のすべてのファンと専門家に挨拶します!



この記事では、私がどのようにクロスプラットフォームでのアニメーションで作業をご紹介しますKivyのフレームワークと連携してGoogleのマテリアルデザインコンポーネントライブラリ- KivyMDKivyプロジェクトの構造を見て、マテリアルコンポーネントを使用して、いくつかのアニメーションを含むテストモバイルアプリケーションを作成します。GIFアニメーションがたくさんある記事は小さくないので、コーヒーを注いで行きましょう!



読者の興味をそそるために、私は私たちが最終的に得たものの結果をすぐに示したいと思います:





したがって、作業にはKivyフレームワークが必要です。



pip install kivy


そして、Kivyフレームワーク用のマテリアルデザインウィジェットを提供するKivyMDライブラリ:



pip install https://github.com/kivymd/KivyMD/archive/master.zip


すべての準備が整いました!PyCharm開いて、次のディレクトリ構造を持つ新しいCallScreenプロジェクト作成しましょう





構造は任意です。KivyフレームワークもKivyMDライブラリも、標準要件以外の必要なディレクトリを必要としませんプロジェクトのルートにmain.pyという名前のファイルが存在する必要がありますこれは、アプリケーションへのエントリポイントです。





data / images ディレクトリに、アプリケーションに必要なグラフィックリソースを配置しました。



ではUIX /画面/基底クラスのディレクトリに、我々は持っていますcallscreen.pyファイル我々はアプリケーションの画面操作のロジックを実装しますのと同じ名前のPythonクラスとを、:





そして、uix / screens / kvディレクトリにcallscreen.kvファイルを作成します(今のところ、空のままにします)-特別なDSL Kivy言語でのUIの説明を含む





プロジェクトが作成されたら、callscreen.pyファイル開いて、テストアプリケーションの画面クラスを実装できます。



callscreen.py:



import os

from kivy.lang import Builder

from kivymd.uix.screen import MDScreen

#    KV 
with open(os.path.join(os.getcwd(), "uix", "screens", "kv", "callscreen.kv"), encoding="utf-8") as KV:
    Builder.load_string(KV.read())


class CallScreen(MDScreen):
    pass


CallScreen クラスKivyMDライブラリのMDScreenウィジェットから継承されます(このライブラリのほとんどすべてのコンポーネントには、MD -Material Designプレフィックスが付いています)。MDScreenは、kivy.uix.screenmanagerモジュールのKivyフレームワークのScreenウィジェットに類似してますが、追加のプロパティがあります。また、MDScreenを使用すると、次のようにウィジェットとコントローラーを上下に配置できます。





これは、フローティング要素を画面に配置するときに使用する配置です。



アプリケーションのエントリポイントであるmain.pyファイルで、必須のビルドメソッドを使用してMDAppクラスから継承されたTestCallScreenクラス作成します。このクラス、ウィジェットまたはレイアウトを返して画面に表示する必要があります。この場合、これは前に作成したCallScreen画面クラスになりますmain.py:







from kivymd.app import MDApp

from uix.screens.baseclass.callscreen import CallScreen


class TestCallScreen(MDApp):
    def build(self):
        return CallScreen()


TestCallScreen().run()


これは、空白の画面を表示する既製のアプリケーションです。main.pyファイルを実行すると、次のように表示されます。





それでは、callscreen.kvファイルでUI画面のマークアップを始めましょうこれを行うには、基本クラスと同じ名前のルールを作成する必要があります。このルールでは、ウィジェットとそのプロパティについて説明します。たとえば、CallScreenというPythonクラスがある場合、KVファイルのルールはまったく同じ名前である必要があります。コード内ですべてのインターフェイス要素を正しく作成できますが、これは、控えめに言っても正しくありません。比較:



MyRootWidget:

    BoxLayout:

        Button:

        Button:


そしてPythonアナログ:



root = MyRootWidget()
box = BoxLayout()
box.add_widget(Button())
box.add_widget(Button())
root.add_widget(box)


ウィジェットツリーがPythonコードよりもKv言語ではるかに読みやすいことは非常に明白です。さらに、ウィジェットの引数が表示されると、Pythonコードが混乱し、1日後にはそれを理解できなくなります。したがって、彼らが何を言っても、フレームワークで宣言的な言語を使用してUI要素を記述できる場合、これはプラスです。Kv言語でもPython命令を実行できるため、Kivyではこれは二重のプラスです。



それでは、タイトル画像から始めましょう:



callscreen.kv:



<CallScreen>

    FitImage:
        id: title_image  # id     
        size_hint_y: .45  #   (45%   )
        #  root     .
        #     <class 'uix.screens.baseclass.callscreen.CallScreen'>,
        #  self -    - <kivymd.utils.fitimage.FitImage object>.
        y: root.height - self.height  #    Y
        source: "data/images/avatar.jpg"  #   




FitImage ウィジェット、画像のアスペクト比を維持しながら、割り当てられたスペース全体に合うように自動的に引き伸ばされます。





main.py ファイル実行して、結果を確認できます





今のところ、すべてが単純であり、ウィジェットのアニメーション化を開始する時が来ました。PythonクラスCallScreencallscreen.kvのアニメーションメソッドが呼び出されるボタンを押して、画面にボタンを追加しましょう







#:import get_color_from_hex kivy.utils.get_color_from_hex
#:import colors kivymd.color_definitions.colors


<CallScreen>

    FitImage:
        [...]

    MDFloatingActionButton:
        icon: "phone"
        x: root.width - self.width - dp(20)
        y: app.root.height * 45 / 100 + self.height / 2
        md_bg_color: get_color_from_hex(colors["Green"]["A700"])
        on_release:
            #     .
            root.animation_title_image(title_image); \
            root.open_call_box = True if not root.open_call_box else False


Kv言語でのモジュールのインポート:



#:import get_color_from_hex kivy.utils.get_color_from_hex
#:import colors kivymd.color_definitions.colors


Pythonコードでの次のインポートに似ています。



#  get_color_from_hex   
#      rgba.
from kivy.utils import get_color_from_hex
#      :
#
# colors = {
#     "Red": {
#         "50": "FFEBEE",
#         "100": "FFCDD2",
#         ...,
#     },
#     "Pink": {
#         "50": "FCE4EC",
#         "100": "F8BBD0",
#         ...,
#     },
#     ...
# }
#
# https://kivymd.readthedocs.io/en/latest/themes/color-definitions/
from kivymd.color_definitions import colors




起動して緑色のボタンをクリックすると、次のようになります-AttributeError: 'CallScreen'オブジェクトには属性 'animation_title_image'がありませんしたがって、基本クラスのCallScreenファイルcallscreen.pyに戻り、その中にメソッドanimation_title_imageを作成して、タイトル画像をアニメーション化します。



callscreen.py:



#     .
from kivy.animation import Animation

[...]

class CallScreen(MDScreen):
    #        .
    open_call_box = False

    def animation_title_image(self, title_image):
        """
        :type title_image: <kivymd.utils.fitimage.FitImage object>
        """

        if not self.open_call_box:
            #       .
            Animation(size_hint_y=1, d=0.6, t="in_out_quad").start(title_image)
        else:
            #       .
            Animation(size_hint_y=0.45, d=0.6, t="in_out_quad").start(title_image)


すでに理解しているように、Animationクラスは、おそらく他のフレームワークと同様に、ウィジェットプロパティをアニメーション化するだけです。この例では、size_hint_yプロパティ(高さのヒント)をアニメーション化し、アニメーションの実行間隔をdパラメーター(duration)に設定し、アニメーションタイプをt -typeパラメーターに設定します。 1つのウィジェットの複数のプロパティを一度にアニメーション化し、演算子++ = ...を使用してアニメーションを組み合わせることができます。次の画像は、作業の結果を示しています。比較のために、適切なGIFには、in_elasticおよびout_elasticアニメーションタイプを使用しました



次のステップは、タイトル画像にぼかし効果を追加することです。これらの目的のために、KivyにはEffectWidgetがありますエフェクトに必要なプロパティを設定し、タイトル画像ウィジェットをEffectWidgetに配置する必要があります。



callscreen.kv:



#:import effect kivy.uix.effectwidget.EffectWidget
#:import HorizontalBlurEffect kivy.uix.effectwidget.HorizontalBlurEffect
#:import VerticalBlurEffect kivy.uix.effectwidget.VerticalBlurEffect


<CallScreen>

    EffectWidget:
        effects:
            # blur_value   .
            (\
            HorizontalBlurEffect(size=root.blur_value), \
            VerticalBlurEffect(size=root.blur_value), \
            )

        FitImage:
            [...]

    MDFloatingActionButton:
        [...]
        on_release:
            #    blur .
            root.animation_blur_value(); \
            [...]


次に、blur_value属性をPython CallScreen基本クラスに追加し、ぼかし効果の値をアニメーション化するanimation_blur_valueメソッド作成する必要があります



callscreen.py:



from kivy.properties import NumericProperty
[...]


class CallScreen(MDScreen):
    #     EffectWidget.
    blur_value = NumericProperty(0)

    [...]

    def animation_blur_value(self):
        if not self.open_call_box:
            Animation(blur_value=15, d=0.6, t="in_out_quad").start(self)
        else:
            Animation(blur_value=0, d=0.6, t="in_out_quad").start(self)


結果:





アニメーションメソッドは非同期で実行されることに注意してください!緑色の呼び出しボタンをアニメーション化して、目を煩わせないようにしましょう。



callscreen.py:



from kivy.utils import get_color_from_hex
from kivy.core.window import Window

from kivymd.color_definitions import colors

[...]


class CallScreen(MDScreen):
    [...]

    def animation_call_button(self, call_button):
        if not self.open_call_box:
            Animation(
                x=self.center_x - call_button.width / 2,
                y=dp(40),
                md_bg_color=get_color_from_hex(colors["Red"]["A700"]),
                d=0.6,
                t="in_out_quad",
            ).start(call_button)
        else:
            Animation(
                y=Window.height * 45 / 100 + call_button.height / 2,
                x=self.width - call_button.width - dp(20),
                md_bg_color=get_color_from_hex(colors["Green"]["A700"]),
                d=0.6,
                t="in_out_quad",
            ).start(call_button)


callscreen.kv:



[...]

<CallScreen>

    EffectWidget:
        [...]

        FitImage:
            [...]

    MDFloatingActionButton:
        [...]
        on_release:
            #     .
            root.animation_call_button(self); \
            [...]




タイプTwoLineAvatarListItemの2つのアイテムをメイン画面に追加しましょう



callscreen.kv:



#:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT
#:import IconLeftWidget kivymd.uix.list.IconLeftWidget

[...]


<ItemList@TwoLineAvatarListItem>
    icon: ""
    font_style: "Caption"
    secondary_font_style: "Caption"
    height: STANDARD_INCREMENT

    IconLeftWidget:
        icon: root.icon


<CallScreen>

    EffectWidget:
        [...]

        FitImage:
            [...]

    MDBoxLayout:
        id: list_box
        orientation: "vertical"
        adaptive_height: True
        y: root.height * 45 / 100 - self.height / 2

        ItemList:
            icon: "phone"
            text: "Phone"
            secondary_text: "123 456 789"

        ItemList:
            icon: "mail"
            text: "Email"
            secondary_text: "kivydevelopment@gmail.com"

    MDFloatingActionButton:
        [...]
        on_release:
            root.animation_list_box(list_box); \
            [...]




2つのItemListアイテムを作成し、それらを垂直ボックスに配置しました。CallScreenクラス新しいメソッドanimation_list_boxを作成して、このボックスをアニメーション化できます。callscreen.py:







[...]


class CallScreen(MDScreen):
    [...]

    def animation_list_box(self, list_box):
        if not self.open_call_box:
            Animation(
                y=-list_box.y,
                opacity=0,
                d=0.6,
                t="in_out_quad"
            ).start(list_box)
        else:
            Animation(
                y=self.height * 45 / 100 - list_box.height / 2,
                opacity=1,
                d=0.6,
                t="in_out_quad",
            ).start(list_box)




画面にツールバーを追加しましょう。



callscreen.kv:



[...]

<CallScreen>

    EffectWidget:
        [...]

        FitImage:
            [...]

    MDToolbar:
        y: root.height - self.height - dp(20)
        md_bg_color: 0, 0, 0, 0
        opposite_colors: True
        title: "Profile"
        left_action_items:  [["menu", lambda x: x]]
        right_action_items: [["dots-vertical", lambda x: x]]

    MDBoxLayout:
        [...]

        ItemList:
            [...]

        ItemList:
            [...]

    MDFloatingActionButton:
        [...]




アバターとユーザー名。



callscreen.kv:



[...]

<CallScreen>

    EffectWidget:
        [...]

        FitImage:
            [...]

    MDToolbar:
        [...]

    MDFloatLayout:
        id: round_avatar
        size_hint: None, None
        size: "105dp", "105dp"
        md_bg_color: 1, 1, 1, 1
        radius: [self.height / 2,]
        y: root.height * 45 / 100 + self.height
        x: root.center_x - (self.width + user_name.width + dp(20)) / 2

        FitImage:
            size_hint: None, None
            size: "100dp", "100dp"
            mipmap: True
            source: "data/images/round-avatar.jpg"
            radius: [self.height / 2,]
            pos_hint: {"center_x": .5, "center_y": .5}
            mipmap: True

    MDLabel:
        id: user_name
        text: "Irene"
        font_style: "H3"
        bold: True
        size_hint: None, None
        -text_size: None, None
        size: self.texture_size
        theme_text_color: "Custom"
        text_color: 1, 1, 1, 1
        y: round_avatar.y + self.height / 2
        x: round_avatar.x + round_avatar.width + dp(20)

    MDBoxLayout:
        [...]

        ItemList:
            [...]

        ItemList:
            [...]

    MDFloatingActionButton:
        root.animation_round_avatar(round_avatar, user_name); \
        root.animation_user_name(round_avatar, user_name); \
        [...]




アバターとユーザー名X位置Y位置の典型的なアニメーション



callscreen.py:



[...]


class CallScreen(MDScreen):
    [...]

    def animation_round_avatar(self, round_avatar, user_name):
        if not self.open_call_box:
            Animation(
                x=self.center_x - round_avatar.width / 2,
                y=round_avatar.y + dp(50),
                d=0.6,
                t="in_out_quad",
            ).start(round_avatar)
        else:
            Animation(
                x=self.center_x - (round_avatar.width + user_name.width + dp(20)) / 2,
                y=self.height * 45 / 100 + round_avatar.height,
                d=0.6,
                t="in_out_quad",
            ).start(round_avatar)

    def animation_user_name(self, round_avatar, user_name):
        if not self.open_call_box:
            Animation(
                x=self.center_x - user_name.width / 2,
                y=user_name.y - STANDARD_INCREMENT,
                d=0.6,
                t="in_out_quad",
            ).start(self.ids.user_name)
        else:
            Animation(
                x=round_avatar.x + STANDARD_INCREMENT,
                y=round_avatar.center_y - user_name.height - dp(20),
                d=0.6,
                t="in_out_quad",
            ).start(user_name)




ボタン付きのボックスを作成する必要があります。





この記事を書いている時点で、必要なボタンがKivyMDライブラリに見つからなかったという事実に出くわしました私はすぐにそれを自分で作らなければなりませんでした。既存のMDIconButtonクラスキャンバス命令を追加し、ボタンの周りに円を定義し、ラベルと一緒に垂直ボックスに配置するだけです。



callscreen.kv:



<CallBoxButton@MDBoxLayout>
    orientation: "vertical"
    adaptive_size: True
    spacing: "8dp"
    icon: ""
    text: ""

    MDIconButton:
        icon: root.icon
        theme_text_color: "Custom"
        text_color: 1, 1, 1, 1

        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Line:
                width: 1
                circle:
                    (\
                    self.center_x, \
                    self.center_y, \
                    min(self.width, self.height) / 2, \
                    0, \
                    360, \
                    )

    MDLabel:
        text: root.text
        size_hint_y: None
        height: self.texture_size[1]
        font_style: "Caption"
        halign: "center"
        theme_text_color: "Custom"
        text_color: 1, 1, 1, 1

[...]




次に、カスタムボタンを格納するボックスを作成します。



callscreen.kv:



<CallBox@MDGridLayout>
    cols: 3
    rows: 2
    adaptive_size: True
    spacing: "24dp"

    CallBoxButton:
        icon: "microphone-off"
        text: "Mute"
    CallBoxButton:
        icon: "volume-high"
        text: "Speaker"
    CallBoxButton:
        icon: "dialpad"
        text: "Keypad"

    CallBoxButton:
        icon: "plus-circle"
        text: "Add call"
    CallBoxButton:
        icon: "call-missed"
        text: "Transfer"
    CallBoxButton:
        icon: "account"
        text: "Contact"

[...]




今、私たちは、作成した配置CallBoxをしてCallScreenのルールに沿ってその位置を設定するY、軸画面の下の境界線を超えて。



callscreen.kv:



[...]

<CallScreen>

    EffectWidget:
        [...]

        FitImage:
            [...]

    MDToolbar:
        [...]

    MDFloatLayout:
        [...]

        FitImage:
            [...]

    MDLabel:
        [...]

    MDBoxLayout:
        [...]

        ItemList:
            [...]

        ItemList:
            [...]

    MDFloatingActionButton:
        root.animation_call_box(call_box, user_name); \
        [...]

    CallBox:
        id: call_box
        pos_hint: {"center_x": .5}
        y: -self.height
        opacity: 0


作成されたボックスの位置をボタンでアニメーション化するだけです。



callscreen.py:



from kivy.metrics import dp
[...]


class CallScreen(MDScreen):
    [...]

    def animation_call_box(self, call_box, user_name):
        if not self.open_call_box:
            Animation(
                y=user_name.y - call_box.height - dp(100),
                opacity=1,
                d=0.6,
                t="in_out_quad",
            ).start(call_box)
        else:
            Animation(
                y=-call_box.height,
                opacity=0,
                d=0.6,
                t="in_out_quad",
            ).start(call_box)






モバイルデバイスでのテストを含む最終的なGIF:





以上で、お役に立てば幸いです。



All Articles