Skip to content

动画效果指南 (Animations) ​


隐式动画 (Implicit animations) ​

使用隐式动画,你可以通过设置目标值来为控件的属性设置动画;每当该目标值发生变化时,控件就会自动为该属性执行从旧值到新值的动画过渡。

动画会在给定的**时间(duration)**内,在旧值和新值之间产生平滑的插值。

默认情况下,动画是以线性(linearly)方式递增的,不过也可以向动画应用特定的曲线(curve),从而根据所提供的曲线来改变动画的变化速率。例如,AnimationCurve.EASE_OUT_CUBIC 曲线在动画开始时会快速增加数值,然后逐渐减速,直到达到目标值:

LayoutControl(及其子类)提供了许多 animate_{something} 属性(如下所述),用于启用其外观的隐式动画:

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

animate_* 属性可以被设置为以下值之一:

  • Animation 实例:允许你自定义动画的播放时长和插值曲线。例如 animate_rotation=Animation(duration=300, curve=AnimationCurve.BOUNCE_OUT)。关于所有可选的插值曲线值,可以参考 Flutter 动画曲线文档。默认值为 AnimationCurve.LINEAR。
  • 整数(int)值:以指定的毫秒数为播放时长,启用 AnimationCurve.LINEAR(线性)曲线的动画。
  • 布尔(bool)值:设置为 True 时,以 1000 毫秒为播放时长,启用 AnimationCurve.LINEAR 曲线的动画。

不透明度动画 (Opacity animation) ​

将控件的 animate_opacity 属性设置为 True、数字或 Animation 类的实例,可以启用 Control.opacity 不透明度属性的隐式动画。

提示

你可以在这里在线尝试。

python
import flet as ft


def main(page: ft.Page):
    def animate_opacity(e: ft.Event[ft.Button]):
        container.opacity = 0 if container.opacity == 1 else 1
        container.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    container := ft.Container(
                        width=150,
                        height=150,
                        bgcolor=ft.Colors.BLUE,
                        border_radius=10,
                        animate_opacity=300,
                    ),
                    ft.Button(
                        content="Animate opacity",
                        on_click=animate_opacity,
                    ),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

不透明度动画效果


旋转动画 (Rotation animation) ​

将控件的 animate_rotation 属性设置为 True、数字或 Animation 类的实例,可以启用 LayoutControl.rotate 旋转属性的隐式动画。

提示

你可以在这里在线尝试。

python
from math import pi

import flet as ft


def main(page: ft.Page):
    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    page.spacing = 30

    def animate(e: ft.Event[ft.Button]):
        container.rotate.angle += pi / 2
        container.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                controls=[
                    container := ft.Container(
                        width=100,
                        height=70,
                        bgcolor=ft.Colors.BLUE,
                        border_radius=5,
                        rotate=ft.Rotate(angle=0, alignment=ft.Alignment.CENTER),
                        animate_rotation=ft.Animation(
                            duration=300,
                            curve=ft.AnimationCurve.BOUNCE_OUT,
                        ),
                    ),
                    ft.Button("Animate!", on_click=animate),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

旋转动画效果


缩放动画 (Scale animation) ​

将控件的 animate_scale 属性设置为 True、数字或 Animation 类的实例,可以启用 LayoutControl.scale 缩放属性的隐式动画。

提示

你可以在这里在线尝试。

python
import flet as ft


def main(page: ft.Page):
    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    page.spacing = 30

    def animate(e: ft.Event[ft.Button]):
        container.scale = 2 if container.scale == 1 else 1
        container.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                controls=[
                    container := ft.Container(
                        width=100,
                        height=100,
                        bgcolor=ft.Colors.BLUE,
                        border_radius=5,
                        scale=1,
                        animate_scale=ft.Animation(
                            duration=600,
                            curve=ft.AnimationCurve.BOUNCE_OUT,
                        ),
                    ),
                    ft.Button("Animate!", on_click=animate),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

缩放动画效果


位移动画 (Offset animation) ​

将控件的 animate_offset 属性设置为 True、数字或 Animation 类的实例,可以启用 LayoutControl.offset 位移属性的隐式动画。

offset 属性是 Offset 类的实例,它指定了控件相对于自身大小的水平 x 和垂直 y 位移量。例如,Offset(-0.25, 0) 的位移将导致控件向左水平平移自身宽度的四分之一。

位移动画常用于各种滑入滑出的滑动效果:

提示

你可以在这里在线尝试。

python
import flet as ft


def main(page: ft.Page):
    def animate(e: ft.Event[ft.Button]):
        container.offset = ft.Offset(0, 0)
        container.update()

    page.add(
        ft.SafeArea(
            content=ft.Container(
                width=150,
                height=150,
                bgcolor=ft.Colors.BLUE,
                border_radius=ft.BorderRadius.all(10),
                offset=ft.Offset(x=-1.1, y=0),
                animate_offset=ft.Animation(
                    duration=600,
                    curve=ft.AnimationCurve.BOUNCE_OUT,
                ),
                    ),
                    ft.Button("Reveal!", on_click=animate),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

位移动画效果


位置动画 (Position animation) ​

将控件的 animate_position 属性设置为 True、数字或 Animation 类的实例,可以启用以下 LayoutControl 定位属性的隐式动画:left、right、bottom、top。

注意

定位属性仅在控件为以下控件的子孙时才会生效:

  1. Stack 控件。
  2. Page.overlay 列表。

提示

你可以在这里在线尝试。

python
import flet as ft


def main(page: ft.Page):
    def animate_container(e: ft.Event[ft.Button]):
        c1.top = 20
        c1.left = 200
        c2.top = 100
        c2.left = 40
        c3.top = 180
        c3.left = 100
        stack.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    stack := ft.Stack(
                        height=400,
                        controls=[
                            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,
                            ),
                        ],
                    ),
                    ft.Button("Animate!", on_click=animate_container),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

位置动画效果


容器自身属性动画 (Animate Container) ​

将 Container.animate 设置为 AnimationValue,可以启用容器自身属性(如大小、背景色、边框样式、渐变色等)的隐式动画。

提示

你可以在这里在线尝试。

python
import flet as ft


def main(page: ft.Page):
    def animate_container(e: ft.Event[ft.Button]):
        container.width = 100 if container.width == 150 else 150
        container.height = 50 if container.height == 150 else 150
        container.bgcolor = (
            ft.Colors.BLUE if container.bgcolor == ft.Colors.RED else ft.Colors.RED
        )
        container.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    container := ft.Container(
                        width=150,
                        height=150,
                        bgcolor=ft.Colors.RED,
                        animate=ft.Animation(
                            duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT
                        ),
                    ),
                    ft.Button("Animate container", on_click=animate_container),
                ]
            )
        ),
    )


if __name__ == "__main__":
    ft.run(main)

Container 属性动画


控件切换动画 (Animated content switcher) ​

AnimatedSwitcher 允许在两个控件(“新”控件和“旧”控件)之间进行带动画效果的过渡切换。

python
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.Button("Animate!", on_click=animate),
    )

ft.run(main)

AnimatedSwitcher 效果


动画结束回调 (Animation end callback) ​

LayoutControl 还带有一个 on_animation_end 事件处理器,它会在动画播放结束时被触发调用。这可以用于实现多个动画链式依次播放的效果。

事件的 data 字段/属性包含了结束的动画类型名称:

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

例如:

python
ft.Container(
    content=ft.Text("Animate me!"),
    animate=ft.Animation(1000, ft.AnimationCurve.BOUNCE_OUT),
    on_animation_end=lambda e: print("Container animation end:", e.data)
)

关注我,学习大模型、大数据、Python等热门技术。