
Pythonプログラミング言語のすべてのファンと専門家に挨拶します!
この記事では、私がどのようにクロスプラットフォームでのアニメーションで作業をご紹介しますKivyのフレームワークと連携してGoogleのマテリアルデザインコンポーネントライブラリ- KivyMD。Kivyプロジェクトの構造を見て、マテリアルコンポーネントを使用して、いくつかのアニメーションを含むテストモバイルアプリケーションを作成します。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クラスCallScreen:callscreen.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:

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



