Skip to content

平台自适应应用 (Adaptive apps) ​


Flet 框架允许你开发平台自适应应用(Adaptive apps),这意味着你可以拥有一套单一的代码库,并且该应用在不同类型的设备平台(如 iOS 和 Android)上运行时,会呈现出完全不同的外观与交互体验。

以下是一个非常简单的应用示例,它在 iOS 和 Android 平台上会显示不同的原生风格外观:

python
import flet as ft

def main(page):

    page.adaptive = True

    page.appbar = ft.AppBar(
        leading=ft.TextButton("New", style=ft.ButtonStyle(padding=0)),
        title=ft.Text("Adaptive AppBar"),
        actions=[
            ft.IconButton(ft.CupertinoIcons.ADD, style=ft.ButtonStyle(padding=0))
        ],
        bgcolor=ft.Colors.with_opacity(0.04, ft.CupertinoColors.SYSTEM_BACKGROUND),
    )

    page.navigation_bar = ft.NavigationBar(
        destinations=[
            ft.NavigationBarDestination(icon=ft.Icons.EXPLORE, label="Explore"),
            ft.NavigationBarDestination(icon=ft.Icons.COMMUTE, label="Commute"),
            ft.NavigationBarDestination(
                icon=ft.Icons.BOOKMARK_BORDER,
                selected_icon=ft.Icons.BOOKMARK,
                label="Bookmark",
            ),
        ],
        border=ft.Border(
            top=ft.BorderSide(color=ft.CupertinoColors.SYSTEM_GREY2, width=0)
        ),
    )

    page.add(
        ft.SafeArea(
            ft.Column(
                [
                    ft.Checkbox(value=False, label="Dark Mode"),
                    ft.Text("First field:"),
                    ft.TextField(keyboard_type=ft.KeyboardType.TEXT),
                    ft.Text("Second field:"),
                    ft.TextField(keyboard_type=ft.KeyboardType.TEXT),
                    ft.Switch(label="A switch"),
                    ft.FilledButton(content=ft.Text("Adaptive button")),
                    ft.Text("Text line 1"),
                    ft.Text("Text line 2"),
                    ft.Text("Text line 3"),
                ]
            )
        )
    )

ft.run(main)

通过仅仅设置 page.adaptive = True,你就可以让你的应用在 iOS 和 Android 设备上都展现出美观的原生外观:

iPhoneAndroid
iPhoneAndroid

Material 与 Cupertino 控件 ​

大多数 Flet 控件是基于 Material Design 规范构建的。

与此同时,Flet 中也提供了一系列 iOS 风格的控件,称为 Cupertino 控件。

Cupertino 控件通常有与之相对应的 Material 控件,后者包含一个默认为 False 的 adaptive 属性。当使用将 adaptive 属性设置为 True 的 Material 控件时,Flet 会根据应用程序运行的系统平台,自动在底层实例化不同的物理控件,例如:

python
ft.Checkbox(adaptive=True, value=True, label="Adaptive Checkbox")

Flet 会检测 Page.platform 属性的值。如果它的值是 PagePlatform.IOS 或 PagePlatform.MACOS,则会创建 iOS 风格的 Cupertino 控件;而在所有其他平台下,则会直接创建 Material 控件。

注意

adaptive 属性可以针对单个控件设置,也可以针对包含子控件的容器控件(如 Row、Column)进行设置。如果一个容器控件被设置为 adaptive=True,那么它的所有子控件都将自动转为自适应风格,除非某个子控件显式地将 adaptive 属性设置为了 False。

Material 对比 Cupertino ​

以下是常见的 Material 控件与其对应的 Cupertino 控件在不同平台下自适应激活时的呈现对比:

控件类型Material 呈现 (Android)Cupertino 呈现 (iOS)
AlertDialogMaterial AlertDialogCupertino AlertDialog
AppBarMaterial AppBarCupertino AppBar
CheckboxMaterial CheckboxCupertino Checkbox
SliderMaterial SliderCupertino Slider
SwitchMaterial SwitchCupertino Switch
RadioMaterial RadioCupertino Radio
TextFieldMaterial TextFieldCupertino TextField

自定义自适应控件 (Custom adaptive controls) ​

虽然 Flet 提供了许多可以通过 adaptive 属性自动适配平台的原生控件,但是在某些情况下,你可能需要进行更细致、更具体的平台适配,例如在不同平台下使用不同的图标、背景色、内边距(padding)等。

在 Flet 中,你可以使用 Python 创建你自己的可重用自定义控件。这些自定义控件只需继承自现有的 Flet 控件,并在内部实现你所需的定制化逻辑。

在下面的示例中,我们创建了一个名为 AdaptiveNavigationBarDestination 的自定义控件,它在 iOS 和 Android 上会显示不同的图标,并将其用作 NavigationBar 的目的地:

python
import flet as ft

class AdaptiveNavigationBarDestination(ft.NavigationBarDestination):
    def __init__(self, ios_icon, android_icon, label):
        super().__init__()
        self._ios_icon = ios_icon
        self._android_icon = android_icon
        self.label = label

    def build(self):
        # 我们可以在 build 方法中检测平台,因为此时 self.page 已经被分配和绑定
        self.icon = (
            self._ios_icon
            if self.page.platform == ft.PagePlatform.IOS
            or self.page.platform == ft.PagePlatform.MACOS
            else self._android_icon
        )

def main(page: ft.Page):
    page.adaptive = True

    page.navigation_bar = ft.NavigationBar(
        selected_index=2,
        destinations=[
            AdaptiveNavigationBarDestination(
                ios_icon=ft.CupertinoIcons.PERSON_3_FILL,
                android_icon=ft.Icons.PERSON,
                label="Contacts",
            ),
            AdaptiveNavigationBarDestination(
                ios_icon=ft.CupertinoIcons.CHAT_BUBBLE_2,
                android_icon=ft.Icons.CHAT,
                label="Chats",
            ),
            AdaptiveNavigationBarDestination(
                ios_icon=ft.CupertinoIcons.SETTINGS,
                android_icon=ft.Icons.SETTINGS,
                label="Settings",
            ),
        ],
    )

    page.update()

ft.run(main)

现在,NavigationBar 及其内部的图标在 iOS 和 Android 上会呈现不同的原生样式:

iOSAndroid
iOS NavigationBarAndroid NavigationBar

提示

你不仅可以根据 Page.platform 进行平台适配,还可以利用 Page.web 属性来为应用是否运行在浏览器中设计不同的 UI 表现形式,甚至组合使用这两种属性来为你的多端应用进行极其精细的界面定制。


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