Hero#
#
New in version 1.0.0.
Use the MDHeroFrom
widget to animate a widget from one
screen to the next.
The hero refers to the widget that flies between screens.
Create a hero animation using KivyMD’s
MDHeroFrom
widget.Fly the hero from one screen to another.
Animate the transformation of a hero’s shape from circular to rectangular while flying it from one screen to another.
The
MDHeroFrom
widget in KivyMD implements a style of animation commonly known as shared element transitions or shared element animations.
The widget that will move from screen A to screen B will be a hero. To move a widget from one screen to another using hero animation, you need to do the following:
On screen A, place the
MDHeroFrom
container.Sets a tag (string) for the
MDHeroFrom
container.Place a hero in the
MDHeroFrom
container.On screen B, place the
MDHeroTo
container - our hero from screen A will fly into this container.
Warning
MDHeroFrom
container cannot have more than one child widget.
Base example#
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreenManager:
MDScreen:
name: "screen A"
md_bg_color: "lightblue"
MDHeroFrom:
id: hero_from
tag: "hero"
size_hint: None, None
size: "120dp", "120dp"
pos_hint: {"top": .98}
x: 24
FitImage:
source: "bg.jpg"
size_hint: None, None
size: hero_from.size
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen B"
MDButtonText:
text: "Move Hero To Screen B"
MDScreen:
name: "screen B"
hero_to: hero_to
md_bg_color: "cadetblue"
MDHeroTo:
id: hero_to
tag: "hero"
size_hint: None, None
size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen A"
MDButtonText:
text: "Move Hero To Screen A"
'''
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
Example().run()
Note that the child of the MDHeroFrom
widget must have the size of the parent:
MDHeroFrom:
id: hero_from
tag: "hero"
FitImage:
size_hint: None, None
size: hero_from.size
To enable hero animation before setting the name of the current screen for the
screen manager, you must specify the name of the tag of the MDHeroFrom
container in which the hero is located:
MDButton:
on_release:
root.current_heroes = ["hero"]
root.current = "screen 2"
MDButtonText:
text: "Move Hero To Screen B"
If you need to switch to a screen that does not contain heroes, set the current_hero attribute for the screen manager as “” (empty string):
MDButton:
on_release:
root.current_heroes = []
root.current = "another screen"
MDButtonText:
text: "Go To Another Screen"
Example#
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreenManager:
MDScreen:
name: "screen A"
md_bg_color: "lightblue"
MDHeroFrom:
id: hero_from
tag: "hero"
size_hint: None, None
size: "120dp", "120dp"
pos_hint: {"top": .98}
x: 24
FitImage:
source: "bg.jpg"
size_hint: None, None
size: hero_from.size
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen B"
MDButtonText:
text: "Move Hero To Screen B"
MDScreen:
name: "screen B"
hero_to: hero_to
md_bg_color: "cadetblue"
MDHeroTo:
id: hero_to
tag: "hero"
size_hint: None, None
size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDButton:
pos_hint: {"center_x": .5}
y: "52dp"
on_release:
root.current_heroes = []
root.current = "screen C"
MDButtonText:
text: "Go To Screen C"
MDButton:
pos_hint: {"center_x": .5}
y: "8dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen A"
MDButtonText:
text: "Move Hero To Screen A"
MDScreen:
name: "screen C"
md_bg_color: "olive"
MDLabel:
text: "Screen C"
halign: "center"
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current = "screen B"
MDButtonText:
text: "Back To Screen B"
'''
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
Example().run()
Events#
Two events are available for the hero:
on_transform_in - when the hero flies from screen A to screen B.
on_transform_out - when the hero back from screen B to screen A.
The on_transform_in, on_transform_out events relate to the
MDHeroFrom
container. For example, let’s change the radius and
background color of the hero during the flight between the screens:
from kivy import utils
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.utils import get_color_from_hex
from kivymd.app import MDApp
from kivymd.uix.hero import MDHeroFrom
from kivymd.uix.relativelayout import MDRelativeLayout
KV = '''
MDScreenManager:
MDScreen:
name: "screen A"
md_bg_color: "lightblue"
MyHero:
id: hero_from
tag: "hero"
size_hint: None, None
size: "120dp", "120dp"
pos_hint: {"top": .98}
x: 24
MDRelativeLayout:
size_hint: None, None
size: hero_from.size
md_bg_color: "blue"
radius: [24, 12, 24, 12]
FitImage:
source: "https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png"
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen B"
MDButtonText:
text: "Move Hero To Screen B"
MDScreen:
name: "screen B"
hero_to: hero_to
md_bg_color: "cadetblue"
MDHeroTo:
id: hero_to
tag: "hero"
size_hint: None, None
size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["hero"]
root.current = "screen A"
MDButtonText:
text: "Move Hero To Screen A"
'''
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
class MyHero(MDHeroFrom):
def on_transform_in(
self, instance_hero_widget: MDRelativeLayout, duration: float
):
'''
Fired when the hero flies from screen **A** to screen **B**.
:param instance_hero_widget: dhild widget of the `MDHeroFrom` class.
:param duration of the transition animation between screens.
'''
Animation(
radius=[12, 24, 12, 24],
duration=duration,
md_bg_color=(0, 1, 1, 1),
).start(instance_hero_widget)
def on_transform_out(
self, instance_hero_widget: MDRelativeLayout, duration: float
):
'''Fired when the hero back from screen **B** to screen **A**.'''
Animation(
radius=[24, 12, 24, 12],
duration=duration,
md_bg_color=get_color_from_hex(utils.hex_colormap["blue"]),
).start(instance_hero_widget)
Example().run()
Usage with ScrollView#
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import StringProperty, ObjectProperty
from kivymd.app import MDApp
from kivymd.uix.hero import MDHeroFrom
KV = '''
<HeroItem>
size_hint_y: None
height: "200dp"
radius: "24dp"
MDSmartTile:
id: tile
size_hint: None, None
size: root.size
on_release: root.on_release()
MDSmartTileImage:
id: image
source: "bg.jpg"
radius: dp(24)
MDSmartTileOverlayContainer:
id: overlay
md_bg_color: 0, 0, 0, .5
adaptive_height: True
padding: "8dp"
spacing: "8dp"
radius: [0, 0, dp(24), dp(24)]
MDLabel:
text: root.tag
theme_text_color: "Custom"
text_color: "white"
adaptive_height: True
MDScreenManager:
md_bg_color: self.theme_cls.backgroundColor
MDScreen:
name: "screen A"
ScrollView:
MDGridLayout:
id: box
cols: 2
spacing: "12dp"
padding: "12dp"
adaptive_height: True
MDScreen:
name: "screen B"
heroes_to: [hero_to]
MDHeroTo:
id: hero_to
size_hint: 1, None
height: "220dp"
pos_hint: {"top": 1}
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = [hero_to.tag]
root.current = "screen A"
MDButtonText:
text: "Move Hero To Screen A"
'''
class HeroItem(MDHeroFrom):
text = StringProperty()
manager = ObjectProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ids.image.ripple_duration_in_fast = 0.05
def on_transform_in(self, instance_hero_widget, duration):
for instance in [
instance_hero_widget,
instance_hero_widget._overlay_container,
instance_hero_widget._image,
]:
Animation(radius=[0, 0, 0, 0], duration=duration).start(instance)
def on_transform_out(self, instance_hero_widget, duration):
for instance, radius in {
instance_hero_widget: [dp(24), dp(24), dp(24), dp(24)],
instance_hero_widget._overlay_container: [0, 0, dp(24), dp(24)],
instance_hero_widget._image: [dp(24), dp(24), dp(24), dp(24)],
}.items():
Animation(
radius=radius,
duration=duration,
).start(instance)
def on_release(self):
def switch_screen(*args):
self.manager.current_heroes = [self.tag]
self.manager.ids.hero_to.tag = self.tag
self.manager.current = "screen B"
Clock.schedule_once(switch_screen, 0.2)
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(12):
hero_item = HeroItem(
text=f"Item {i + 1}", tag=f"Tag {i}", manager=self.root
)
if not i % 2:
hero_item.md_bg_color = "lightgrey"
self.root.ids.box.add_widget(hero_item)
Example().run()
Using multiple heroes at the same time#
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreenManager:
MDScreen:
name: "screen A"
md_bg_color: "lightblue"
MDHeroFrom:
id: hero_kivymd
tag: "kivymd"
size_hint: None, None
size: "200dp", "200dp"
pos_hint: {"top": .98}
x: 24
FitImage:
source: "avatar.png"
size_hint: None, None
size: hero_kivymd.size
radius: self.height / 2
MDHeroFrom:
id: hero_kivy
tag: "kivy"
size_hint: None, None
size: "200dp", "200dp"
pos_hint: {"top": .98}
x: 324
FitImage:
source: "bg.jpg"
size_hint: None, None
size: hero_kivy.size
radius: self.height / 2
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["kivymd", "kivy"]
root.current = "screen B"
MDButtonText:
text: "Move Hero To Screen B"
MDScreen:
name: "screen B"
heroes_to: hero_to_kivymd, hero_to_kivy
md_bg_color: "cadetblue"
MDHeroTo:
id: hero_to_kivy
tag: "kivy"
size_hint: None, None
pos_hint: {"center_x": .5, "center_y": .5}
MDHeroTo:
id: hero_to_kivymd
tag: "kivymd"
size_hint: None, None
pos_hint: {"right": 1, "top": 1}
MDButton:
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["kivy", "kivymd"]
root.current = "screen A"
MDButtonText:
text: "Move Hero To Screen A"
'''
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Example().run()
API - kivymd.uix.hero
#
- class kivymd.uix.hero.MDHeroFrom(**kwargs)#
The container from which the hero begins his flight.
For more information, see in the
MDBoxLayout
class documentation.- Events:
- on_transform_in
when the hero flies from screen A to screen B.
- on_transform_out
Fired when the hero back from screen B to screen A.
- tag#
Tag ID for heroes.
tag
is anStringProperty
and defaults to ‘’.
- on_transform_in(*args)#
Fired when the hero flies from screen A to screen B.
- on_transform_out(*args)#
Fired when the hero back from screen B to screen A.
- class kivymd.uix.hero.MDHeroTo(*args, **kwargs)#
The container in which the hero comes.
For more information, see in the
MDBoxLayout
class documentation.- tag#
Tag ID for heroes.
tag
is anStringProperty
and defaults to ‘’.