Skip to content

Image 继承自:LayoutControl, Control, BaseControl

显示图像。

支持以下常见格式:JPEG、PNG、SVG、 GIF、动图 GIF、WebP、动图 WebP、BMP 和 WBMP。

示例:

python
ft.Image(
    src="https://flet.dev/img/logo.svg",
    width=100,
    height=100,
)

示例 ​

python
import flet as ft


def main(page: ft.Page):
    page.title = "Image Example"
    page.theme_mode = ft.ThemeMode.LIGHT
    page.padding = 50

    gallery = ft.Row(expand=True, wrap=False, scroll=ft.ScrollMode.ALWAYS)

    for i in range(0, 30):
        gallery.controls.append(
            ft.Image(
                src=f"https://picsum.photos/200/200?{i}",
                width=200,
                height=200,
                fit=ft.BoxFit.NONE,
                repeat=ft.ImageRepeat.NO_REPEAT,
                border_radius=ft.BorderRadius.all(10),
            )
        )

    page.add(
        ft.SafeArea(
            expand=True,
            content=ft.Column(
                expand=True,
                controls=[
                    ft.Image(
                        src="assets/app_icon_512.png",
                        width=100,
                        height=100,
                        fit=ft.BoxFit.CONTAIN,
                    ),
                    gallery,
                ],
            ),
        )
    )


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

import flet as ft


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

    def show_random(e: ft.Event[ft.Button]):
        image.src = f"https://picsum.photos/320/200?random={time.time()}"  # random
        image.update()

    page.add(
        ft.SafeArea(
            content=ft.Column(
                horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                controls=[
                    image := ft.Image(
                        src="https://picsum.photos/320/200?random=1",
                        width=360,
                        height=220,
                        fit=ft.BoxFit.COVER,
                        # solid blue image as bas64
                        placeholder_src="data:image/png;base64,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",  # noqa: E501
                        placeholder_fade_out_animation=ft.Animation(
                            duration=ft.Duration(milliseconds=900),
                            curve=ft.AnimationCurve.EASE_OUT,
                        ),
                        fade_in_animation=ft.Animation(
                            duration=ft.Duration(milliseconds=700),
                            curve=ft.AnimationCurve.EASE_IN_OUT,
                        ),
                    ),
                    ft.Button("Show random image", on_click=show_random),
                ],
            ),
        )
    )


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

import flet as ft


def main(page: ft.Page):
    # image as base64 string
    base64_src = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC"  # noqa: E501
    # image as bytes
    bytes_src = base64.b64decode(base64_src)

    page.add(
        ft.SafeArea(
            content=ft.Row(
                controls=[
                    ft.Image(
                        src=base64_src,
                        width=100,
                        height=100,
                    ),
                    ft.Image(
                        src=bytes_src,
                        width=100,
                        height=100,
                    ),
                ],
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)
python
import flet as ft


def main(page: ft.Page):
    svg_image = """
<svg version="1.1" id="Layer_1"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    x="0px" y="0px"
    viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<g>
    <path d="M14.43339,18.88085c2.15923,0,3.91203-1.7476,3.91203-3.91226
        c0-2.15805-1.7528-3.90566-3.91723-3.90566
        c-0.74107,0-1.43221,0.21538-2.02332,0.57576c0.18598-0.05526,0.37562-0.09493,0.58084-0.09493
        c1.09756,0,1.98365,0.88609,1.98365,1.98235c0,1.09248-0.88608,1.98376-1.98365,1.98376
        c-1.09627,0-1.98235-0.88608-1.98235-1.98376c0-0.20499,0.03979-0.39486,0.09493-0.58096
        c-0.36027,0.59135-0.57576,1.28236-0.57576,2.02344C10.52254,17.13325,12.27026,18.88085,14.43339,18.88085z"/>
    <path d="M24.55235,1.00006H5.44812C2.99534,1.00006,
        1,2.99563,1,5.44747v19.10459c0,2.45278,1.99533,4.44788,4.44812,4.44788
        h19.10423c2.45243,0,4.44765-1.9951,4.44765-4.44788V5.44747C29,2.99563,27.00479,1.00006,24.55235,1.00006z
        M27.32951,24.55206
        c0,1.53175-1.246,2.77774-2.77715,2.77774H5.44812c-1.53151,0-2.77751-1.246-2.77751-2.77774v-8.83719h4.08065
        c0.37644,3.90943,3.67563,6.97482,7.67705,6.97482c4.00709,0,7.3065-3.06539,7.68295-6.97482h5.21824V24.55206z
        M8.36366,14.96859
        c0-3.34831,2.7161-6.06418,6.06453-6.06418c3.35469,0,6.07079,2.71587,6.07079,6.06418c0,3.35492-2.7161,6.07079-6.07079,6.07079
        C11.07977,21.03938,8.36366,18.32351,8.36366,14.96859z
        M27.32951,13.75472h-5.28579
        c-0.58568-3.67705-3.77116-6.5006-7.61541-6.5006c-3.83882,0-7.02383,2.82356-7.60951,6.5006H2.67061V5.44747
        c0-1.53128,1.246-2.7768,2.77751-2.7768h19.10423c1.53116,0,2.77715,1.24552,2.77715,2.7768V13.75472z"/>
    <path d="M24.06196,5.11637h-1.75185c-0.48236,0-0.87593,0.39345-0.87593,
        0.87569v1.75186
        c0,0.48225,0.39356,0.87616,0.87593,0.87616h1.75186c0.47776,0,0.87038-0.39392,0.87038-0.87616V5.99205
        C24.93234,5.50982,24.53972,5.11637,24.06196,5.11637z"/>
</g>
</svg>"""

    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    ft.Image(
                        src="https://raw.githubusercontent.com/dnfield/flutter_svg/master/packages/flutter_svg/example/assets/wikimedia/Firefox_Logo_2017.svg",
                        width=200,
                        height=200,
                    ),
                    ft.Image(
                        src=svg_image,
                        width=100,
                        height=100,
                        color=ft.Colors.RED,
                    ),
                    ft.Image(
                        src=svg_image,
                        width=100,
                        height=100,
                        color=ft.Colors.BLUE,
                    ),
                    ft.Container(
                        bgcolor=ft.Colors.BLACK_87,
                        border_radius=5,
                        content=ft.Image(
                            src=svg_image,
                            width=100,
                            height=100,
                            color=ft.Colors.WHITE,
                        ),
                    ),
                ],
            ),
        )
    )


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

import flet as ft


async def main(page: ft.Page):
    svg_image = """
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
 <g>
  <ellipse ry="{}" rx="{}" id="svg_1" cy="200" cx="200" stroke="#000" fill="#fff"/>
 </g>
</svg>
"""

    img = ft.Image(src=svg_image.format(0, 0))
    page.add(ft.SafeArea(content=img))

    for _ in range(0, 10):
        for i in range(0, 10):
            img.src = svg_image.format(i * 10, i * 10)
            img.update()
            await asyncio.sleep(0.1)


if __name__ == "__main__":
    ft.run(main)
python
import flet as ft

"""
- Browse Lucide icons: https://lucide.dev/
- Copy SVG and use it as value for `Image.src`
"""


def main(page: ft.Page):
    page.add(
        ft.SafeArea(
            content=ft.Row(
                controls=[
                    ft.Image(
                        src='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5"></path><path d="M16 2v4"></path><path d="M8 2v4"></path><path d="M3 10h5"></path><path d="M17.5 17.5 16 16.25V14"></path><path d="M22 16a6 6 0 1 1-12 0 6 6 0 0 1 12 0Z"></path></svg>',  # noqa: E501
                        color=ft.Colors.PINK,
                    ),
                    ft.Image(
                        src='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>',  # noqa: E501
                        color=ft.Colors.GREEN,
                    ),
                ],
            ),
        )
    )


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

import flet as ft


def get_new_image_src() -> str:
    random_id = random.randint(1, 85)
    return f"https://picsum.photos/id/{random_id}/1280/720"


def main(page: ft.Page):
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    initial_src = get_new_image_src()
    image_with_gapless = ft.Image(
        src=initial_src,
        width=340,
        height=220,
        fit=ft.BoxFit.COVER,
        gapless_playback=True,
    )
    image_without_gapless = ft.Image(
        src=initial_src,
        width=340,
        height=220,
        fit=ft.BoxFit.COVER,
        gapless_playback=False,
    )

    def image_panel(title: str, image: ft.Image):
        return ft.Column(
            spacing=8,
            width=340,
            horizontal_alignment=ft.CrossAxisAlignment.CENTER,
            controls=[
                ft.Text(title, weight=ft.FontWeight.BOLD),
                ft.Container(
                    content=image,
                    bgcolor=ft.Colors.BLUE_GREY_900,
                    border_radius=ft.BorderRadius.all(12),
                    clip_behavior=ft.ClipBehavior.ANTI_ALIAS,
                ),
            ],
        )

    def next_photo(e: ft.Event[ft.Button]):
        new_src = get_new_image_src()
        image_with_gapless.src = new_src
        image_without_gapless.src = new_src
        image_with_gapless.update()
        image_without_gapless.update()

    page.appbar = ft.AppBar(title="Gapless Playback Showcase")
    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    ft.Text(
                        "Click 'Load next photo' to switch both images to a new URL.\n"
                        "The left/top image keeps showing the previous frame while "
                        "loading "
                        "the next one. This is referred to as gapless playback.",
                        text_align=ft.TextAlign.CENTER,
                    ),
                    ft.Row(
                        wrap=True,
                        spacing=20,
                        run_spacing=20,
                        alignment=ft.MainAxisAlignment.CENTER,
                        controls=[
                            image_panel("gapless_playback=True", image_with_gapless),
                            image_panel(
                                "gapless_playback=False",
                                image_without_gapless,
                            ),
                        ],
                    ),
                    ft.FilledButton("Load next photo", on_click=next_photo),
                ],
            ),
        )
    )


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

属性 ​

名称类型默认值说明
srcUnion[str, bytes]必填图像源。可以是以下之一: - URL 或本地静态资源文件路径; - base64 字符串; - 原始字节。
error_contentOptional[Control]None当图像无法从提供的源加载时显示的备用控件。
repeatImageRepeatImageRepeat.NO_REPEAT当图像未覆盖布局边界的某些部分时,如何绘制这些部分。
fitOptional[BoxFit]None定义如何将此图像嵌入到布局期间分配的空间中。
border_radiusOptional[BorderRadiusValue]None将图像裁剪为圆角。
colorOptional[ColorValue]None如果设置了该值,此颜色会使用 color_blend_mode 与每个图像像素混合。
color_blend_modeOptional[BlendMode]None用于将 color 与图像组合。就混合模式而言,color 是源,此图像是目标。
gapless_playbackboolFalse当图像提供者发生变化时,是继续显示旧图像(True),还是短暂显示空白(False)。对 svg 图像无效果。
semantics_labelOptional[str]None此图像的语义描述。用于在 Android 上向 TalkBack、在 iOS 上向 VoiceOver 提供图像描述。
exclude_from_semanticsboolFalse是否将此图像从语义信息中排除。
filter_qualityFilterQualityFilterQuality.MEDIUM图像的渲染质量。
placeholder_srcOptional[Union[str, bytes]]None图像加载期间显示的占位图。可以是以下之一: - URL 或本地静态资源文件路径; - base64 字符串; - 原始字节。如果为 None,加载期间不显示占位图;src 会直接出现(如果 placeholder_src 或 placeholder_fade_out_animation 不为 None,则淡入)。注意:目前不支持将 SVG 源用作占位图。如果提供了 SVG,此属性将被忽略,改为直接显示 src。
placeholder_fitOptional[BoxFit]None定义如何将占位图嵌入其空间中。如果为 None,默认为 fit。
fade_in_animationOptional[Animation]Nonesrc 图像在加载完成后出现、替换 placeholder_src 时的淡入动画。如果为 None,且 placeholder_src 或 placeholder_fade_out_animation 不为 None,则默认为 Animation(Duration(milliseconds=250), AnimationCurve.EASE_IN_OUT)。
placeholder_fade_out_animationOptional[Animation]Nonesrc 加载完成后,placeholder_src 的淡出动画。如果为 None,且 placeholder_src 或 fade_in_animation 不为 None,则默认为 Animation(Duration(milliseconds=150), AnimationCurve.EASE_OUT)。
cache_widthOptional[int]None图像解码时的尺寸。但无论此参数如何,图像都会被渲染到布局的约束尺寸中。
cache_heightOptional[int]None图像解码时的尺寸。但无论此参数如何,图像都会被渲染到布局的约束尺寸中。
anti_aliasboolFalse是否以抗锯齿方式绘制图像。抗锯齿可以减轻图像旋转时出现的锯齿伪影。
widthOptional[Number]None控件的强制宽度(以虚拟像素为单位)。
heightOptional[Number]None控件的强制高度(以虚拟像素为单位)。
leftOptional[Number]None子控件左边缘相对于 Stack 左侧的内缩距离。注意:仅当此控件是以下之一的后代时才生效:Stack 控件、overlay 列表。
topOptional[Number]None子控件上边缘相对于 Stack 顶部的内缩距离。注意:仅当此控件是以下之一的后代时才生效:Stack 控件、overlay 列表。
rightOptional[Number]None子控件右边缘相对于 Stack 右侧的内缩距离。注意:仅当此控件是以下之一的后代时才生效:Stack 控件、overlay 列表。
bottomOptional[Number]None子控件下边缘相对于 Stack 底部的内缩距离。注意:仅当此控件是以下之一的后代时才生效:Stack 控件、overlay 列表。
alignOptional[Alignment]None控件在其父级中的对齐方式。
marginOptional[MarginValue]None设置控件的外边距。
rotateOptional[RotateValue]None围绕控件中心旋转来变换此控件。rotate 属性的值可以是以下类型之一: * number —— 顺时针旋转的弧度值。整圈 360° 为 math.pi * 2 弧度,90° 为 pi / 2,45° 为 pi / 4,以此类推。 * Rotate —— 允许同时指定旋转 angle 和 alignment,即旋转中心的位置。 示例: python ft.Image( src="https://picsum.photos/100/100", width=100, height=100, border_radius=5, rotate=Rotate(angle=0.25 * pi, alignment=ft.Alignment.CENTER_LEFT) )
scaleOptional[ScaleValue]None沿二维平面缩放此控件。默认缩放因子为 1.0,表示不缩放。 例如,将此属性设为 0.5 会让控件缩小一半,而设为 2.0 则会放大一倍。 通过将 Control.scale 属性设为 Scale 类的实例,可以为 x 和 y 轴指定不同的缩放倍数。可以指定 scale,或者指定 scale_x 和 scale_y,但不能同时指定全部。 示例: python ft.Image( src="https://picsum.photos/100/100", width=100, height=100, border_radius=5, scale=ft.Scale(scale_x=2, scale_y=0.5) )
offsetOptional[OffsetValue]None在绘制控件之前应用平移变换。 平移量表示为按控件尺寸缩放的 Offset。例如,Offset(x=0.25, y=0) 会使控件沿水平方向平移其宽度的四分之一。 示例 下面的示例把容器显示在 Stack 的 0, 0 左上角,因为变换对控件应用了 -1 * 100, -1 * 100(即 offset * control's size)的水平与垂直平移: python import flet as ft def main(page: ft.Page): page.add( ft.Stack( width=1000, height=1000, controls=[ ft.Container( bgcolor=ft.Colors.RED, width=100, height=100, left=100, top=100, offset=ft.Offset(-1, -1), ) ], ) ) ft.run(main)
flipOptional[Flip]None水平方向和/或垂直方向翻转此控件。设为 Flip 的实例即可沿 x 轴、y 轴或两者镜像翻转。
transformOptional[Transform]None对此控件应用通用矩阵变换。设为带 Matrix4 记录的 Transform 实例,用以描述任意的变换序列。
aspect_ratioOptional[Number]None控件的宽高比,定义为 width 与 height 的比值。注意:在当前实现中,如果设置了 aspect_ratio,同一控件上的 width 和 height 将在最终渲染尺寸中被忽略。
animate_opacityOptional[AnimationValue]None启用 opacity 属性的隐式动画。更多信息见此处。
animate_sizeOptional[AnimationValue]None启用此控件尺寸的隐式动画。如果设置了 width 或 height,则这些维度的变化会以动画呈现。如果两者都未设置,则对控件自然尺寸的变化进行动画。更多信息见此处。
animate_positionOptional[AnimationValue]None启用定位属性(left、right、top 和 bottom)的隐式动画。更多信息见此处。
animate_alignOptional[AnimationValue]None启用 align 属性的隐式动画。更多信息见此处。
animate_marginOptional[AnimationValue]None启用 margin 属性的隐式动画。更多信息见此处。
animate_rotationOptional[AnimationValue]None启用 rotate 属性的隐式动画。更多信息见此处。
animate_scaleOptional[AnimationValue]None启用 scale 属性的隐式动画。更多信息见此处。
animate_offsetOptional[AnimationValue]None启用 offset 属性的隐式动画。更多信息见此处。
size_change_intervalint10on_size_change 事件的采样间隔(毫秒)。设为 0 时,每次变化都会立即调用 on_size_change。
expandAnnotated[Optional[Union[bool, int]], V.instance_of((bool, int))]None指定此控件是否/如何扩展以填满父布局中的可用空间。更多信息见此处。注意:仅当此控件的直接父级是以下控件或其子类时才生效:Column、Row、View、Page。抛出异常:ValueError:如果它不是 bool 或 int 类型。
expand_looseboolFalse允许控件在主轴方向有可用空间时扩展,但不要求它填满所有可用空间。更多信息见此处。注意:如果 expand_loose 为 True,则仅在以下条件满足时才生效: - expand 不为 None,且 - 此控件的直接父级是以下控件或其子类之一:Column、Row、View、Page。
colResponsiveNumber12如果此控件的父级是 ResponsiveRow,则此属性决定该控件在屏幕上跨越多少虚拟列。可以是一个数字,也可以是一个按断点配置不同值的字典,例如 col={"sm": 6}。值为 0 时会在该断点隐藏控件,因此它不会占用父级 ResponsiveRow 中的任何列。此控件默认跨越 12 个虚拟列。 | 断点 | 尺寸 | |---|---| | xs | <576px | | sm | ≥576px | | md | ≥768px | | lg | ≥992px | | xl | ≥1200px | | xxl | ≥1400px |
opacityAnnotated[Number, V.between(0.0, 1.0)]1.0定义控件的透明度。取值范围从 0.0(完全透明)到 1.0(完全不透明,无任何透明感)。抛出异常:ValueError:如果它不在 0.0 到 1.0(含)之间。
tooltipOptional[TooltipValue]None鼠标悬停在此控件上时显示的工具提示。
badgeOptional[BadgeValue]None显示在此控件顶部的徽章。
visibleboolTrue每个控件都有 visible 属性,默认为 True —— 控件会渲染在页面上。将 visible 设为 False 会彻底阻止控件(及其所有子控件,如果有)渲染到页面画布上。隐藏的控件无法通过键盘或鼠标获得焦点或选中,也不会触发任何事件。
disabledboolFalse每个控件都有 disabled 属性,默认为 False —— 控件及其所有子控件都处于启用状态。注意:此属性的值会递归向下传播到所有子控件。示例:例如,如果你有一个包含多个输入控件的表单,可以通过禁用容器来一并禁用它们: python ft.Column( disabled = True, controls=[ ft.TextField(), ft.TextField() ] )
rtlboolFalse控件的文本方向是否为从右到左(RTL)。
dataAnyskip_任意类型的自定义数据。
keyOptional['KeyValue']None用于在更新之间保持控件标识稳定的键。

只读属性 ​

名称类型默认值说明
parentOptional['BaseControl']—此控件的直接祖先(父级)。默认为 None,只有在此控件被挂载(加入页面树)后才有值。Page 控件(页面树的根)是个例外 —— 它的 parent 始终为 None。
page'Page'—此控件所属的页面。

事件 ​

名称类型默认值说明
on_size_changeOptional[EventHandler[LayoutSizeChangeEvent['LayoutControl']]]None当此控件的尺寸发生变化时调用。size_change_interval 定义此事件的调用频率。
on_animation_endOptional[ControlEventHandler['LayoutControl']]None动画完成时调用。可用于串联多个动画。事件处理器参数的 data 属性包含动画名称。更多信息见此处。

方法 ​

名称类型默认值说明
init———
is_isolated——返回此控件是否被标记为隔离。隔离控件会被排除在父级驱动的更新遍历之外,并需要自行管理更新边界。
build——在控件初始化期间调用一次,用于定义其子控件。在此方法中 page 属性可用。
before_update——每当此控件被更新时都会调用此方法。注意:务必不要在此处调用或请求 update()。
before_event——在事件处理器执行之前拦截事件。返回 False 可取消分发。返回 True 或 None 则继续正常的事件处理。
did_mount——在控件挂载到页面树之后调用。重写此方法以启动需要已挂载页面的资源,例如订阅、定时器或服务监听器。
will_unmount——在控件从页面树移除之前调用。重写此方法以释放 did_mount() 中创建的资源,例如订阅、定时器或外部句柄。
get_data_channel——解析为此 widget 在 Dart 侧分配的 [DataChannel]。模式: on_data_channel_open: Optional[ft.EventHandler[DataChannelOpenEvent]] = None def init(self): self.on_data_channel_open = self._on_open def _on_open(self, e): self._channel = self.get_data_channel(e.channel_id) 幂等 —— 底层的 Connection 会按 id 缓存 DataChannel,因此重复调用会返回同一实例。没有错误路径:该 id 始终来自框架触发的事件,所以当此方法运行时,通道在两端都已存在。
updateNone—为此控件请求一次 UI 更新。在更改控件状态或属性后调用。控件必须已挂载到页面且未被标记为冻结。

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