跳到主要内容

动画 Animations

隐式动画

使用隐式动画,您可以通过设置目标值来对控件属性进行动画处理;每当目标值发生变化时,控件都会将属性从旧值动画处理到新值。动画会在给定的持续时间内产生旧值和新值之间的插值。默认情况下,动画会以线性方式递增动画值,但是可以应用曲线到动画上,以根据所提供的曲线来改变值。例如,easeOutCubic 曲线会在动画开始时快速递增动画值,然后在达到目标值之前逐渐减慢速度:

每个 Control 都提供了一些 animate_{something} 属性,下面详细描述了其用途,以实现控件外观的隐式动画效果:

  • animate_opacity
  • animate_rotation
  • animate_scale
  • animate_offset
  • animate_position
  • animate(Container)

animate_* 属性可以具有以下值之一:

  • animation.Animation 类的实例 - 允许配置动画的持续时间(以毫秒为单位)和曲线,例如 animate_rotation=ft.animation.Animation(duration=300, curve="bounceOut")。请参阅 Flutter 文档中的 Curves 以了解可能的值。默认值是 linear
  • int 值 - 启用具有指定持续时间(以毫秒为单位)和 linear 曲线的动画。
  • bool 值 - 启用具有持续时间为 1000 毫秒和 linear 曲线的动画。

不透明度动画

将控件的 animate_opacity 设置为 True、数字或 animation.Animation 类的实例(参见上述内容)将启用 Control.opacity 属性的隐式动画效果。

import flet as ft

def main(page: ft.Page):

c = ft.Container(
width=150,
height=150,
bgcolor="blue",
border_radius=10,
animate_opacity=300,
)

def animate_opacity(e):
c.opacity = 0 if c.opacity == 1 else 1
c.update()

page.add(
c,
ft.ElevatedButton(
"Animate opacity",
on_click=animate_opacity,
),
)

ft.app(target=main)

旋转动画

将控件的animate_rotation设置为True、数字或animation.Animation类的实例(请参见上文)可以启用对Control.rotate属性的隐式动画。

from math import pi
import flet as ft

def main(page: ft.Page):

c = ft.Container(
width=100,
height=70,
bgcolor="blue",
border_radius=5,
rotate=ft.transform.Rotate(0, alignment=ft.alignment.center),
animate_rotation=ft.animation.Animation(300, ft.AnimationCurve.BOUNCE_OUT),
)

def animate(e):
c.rotate.angle += pi / 2
page.update()

page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.spacing = 30
page.add(
c,
ft.ElevatedButton("Animate!", on_click=animate),
)

ft.app(target=main)

缩放动画

将控件的animate_scale设置为True、数字或animation.Animation类的实例(请参见上文)可以启用对Control.scale属性的隐式动画。

import flet as ft

def main(page: ft.Page):

c = ft.Container(
width=100,
height=100,
bgcolor="blue",
border_radius=5,
scale=ft.transform.Scale(scale=1),
animate_scale=ft.animation.Animation(600, ft.AnimationCurve.BOUNCE_OUT),
)

def animate(e):
c.scale = 2
page.update()

page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.spacing = 30
page.add(
c,
ft.ElevatedButton("Animate!", on_click=animate),
)

ft.app(target=main)

偏移动画

将控件的animate_offset设置为True、数字或animation.Animation类的实例(请参见上文)可以启用对Control.offset属性的隐式动画。

offset属性是transform.Offset类的实例,用于指定控件缩放后的水平x和垂直y偏移量。例如,偏移transform.Offset(-0.25, 0)将导致控件水平移动到其宽度的四分之一处。

偏移动画用于各种滑动效果:

import flet as ft

def main(page: ft.Page):

c = ft.Container(
width=150,
height=150,
bgcolor="blue",
border_radius=10,
offset=ft.transform.Offset(-2, 0),
animate_offset=ft.animation.Animation(1000),
)

def animate(e):
c.offset = ft.transform.Offset(0, 0)
c.update()

page.add(
c,
ft.ElevatedButton("Reveal!", on_click=animate),
)

ft.app(target=main)

位置动画

将控件的animate_position设置为True、数字或animation.Animation类的实例(请参见上文)可以启用对控件的lefttoprightbottom属性的隐式动画。

请注意,控件位置仅在Stack控件内起作用。

import flet as ft

def main(page: ft.Page):

c1 = ft.Container(width=50, height=50, bgcolor="red", animate_position=1000)

c2 = ft.Container(
width=50, height=50, bgcolor="green", top=60, left=0, animate_position=500
)

c3 = ft.Container(
width=50, height=50, bgcolor="blue", top=120, left=0, animate_position=1000
)

def animate_container(e):
c1.top = 20
c1.left = 200
c2.top = 100
c2.left = 40
c3.top = 180
c3.left = 100
page.update()

page.add(
ft.Stack([c1, c2, c3], height=250),
ft.ElevatedButton("Animate!", on_click=animate_container),
)

ft.app(target=main)

动画容器

Container.animate设置为True、数字或animation.Animation类的实例(请参见上文)可以启用对容器属性(如大小、背景颜色、边框样式、渐变)的隐式动画。

import flet as ft

def main(page: ft.Page):

c = ft.Container(
width=150,
height=150,
bgcolor="red",
animate=ft.animation.Animation(1000, ft.AnimationCurve.BOUNCE_OUT),
)

def animate_container(e):
c.width = 100 if c.width == 150 else 150
c.height = 50 if c.height == 150 else 150
c.bgcolor = "blue" if c.bgcolor == "red" else "red"
c.update()

page.add(c, ft.ElevatedButton("Animate container", on_click=animate_container))

ft.app(target=main)

动画内容切换器

AnimatedSwitcher允许在新控件和之前设置在AnimatedSwitcher上的控件之间进行动画过渡。

import time

import flet as ft

def main(page: ft.Page):

i = ft.Image(src="https://picsum.photos/150/150", width=150, height=150)

def animate(e):
sw.content = ft.Image(
src=f"https://picsum.photos/150/150?{time.time()}", width=150, height=150
)
page.update()

sw = ft.AnimatedSwitcher(
i,
transition=ft.AnimatedSwitcherTransition.SCALE,
duration=500,
reverse_duration=500,
switch_in_curve=ft.AnimationCurve.BOUNCE_OUT,
switch_out_curve=ft.AnimationCurve.BOUNCE_IN,
)

page.add(
sw,
ft.ElevatedButton("Animate!", on_click=animate),
)

ft.app(target=main)

动画结束回调

所有具有animate_*属性的控件都具有on_animation_end事件处理程序,当动画完成时调用该处理程序,可以用于链接多个动画。

事件的data字段包含动画的名称:

  • opacity
  • rotation
  • scale
  • offset
  • position
  • container

例如:

c = ft.Container(
ft.Text("Animate me!"),
# ...
animate=ft.animation.Animation(1000, "bounceOut"),
on_animation_end=lambda e: print("Container animation end:", e.data)
)