Skip to main content

Adaptive apps

Flet framework allows you to develop adaptive apps which means having a single codebase that will deliver different look depending on the device's platform.

Below is the example of a very simple app that has a different look on iOS and Android platforms:

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.cupertino_icons.ADD, style=ft.ButtonStyle(padding=0))
],
bgcolor=ft.colors.with_opacity(0.04, ft.cupertino_colors.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.cupertino_colors.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.app(main)

By setting just page.adaptive = True you can make you app looking awesome on both iOS and Android devices:

iPhone

Android

Material and Cupertino controls

Most of Flet controls are based on Material design.

There is also a number of iOS-style controls in Flet that are called Cupertino controls.

Cupertino controls usually have a matching Material control that has adaptive property which defaults toFalse. When using a Material control with adaptive property set to True, a different control will be created depending on the platform, for example:

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

Flet checks the value of page.platform property and if it is ft.PagePlatform.IOS or ft.PagePlatform.MACOS, Cupertino control will be created; in all other cases Material control will be created.

note

adaptive property can be set for an individual control or a container control such as Row, Column or any other control that has content or controls property. If container control is adaptive, all its child controls will be adaptive, unless adaptive property is explicitly set to False for a child control.

Below is the list of adaptive Material controls and their matching Cupertino controls:

Custom adaptive controls

While Flet offers a number of controls that will be adapted to a platform automatically using their adaptive property, there will be cases when you need more specific adaptive UI presentation, for example, using different icon, background color, padding etc. depending on the platform.

With Flet, you can create your own reusable custom controls in Python that will inherit from a Flet control and implement specific properties you need. In the example below, we are creating a new AdaptiveNavigationBarDestination control that will be displaying different icon on iOS and Android:

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):
# we can check for platform in build method because self.page is known
self.icon = (
self._ios_icon
if self.page.platform == ft.PagePlatform.IOS
or self.page.platform == ft.PagePlatform.MACOS
else self._android_icon
)

We will use AdaptiveNavigationBarDestination in NavigationBar:

import flet as ft
from adaptive_navigation_destination import AdaptiveNavigationBarDestination

def main(page):

page.adaptive = True

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

page.update()


ft.app(main)

Now the NavigationBar and icons within it will look like different on Android and iOS:

iOS

Android

note

You may utilise reusable controls approach to adapt your app not only depending on the platform but also use page.web property to have different UI depending on wether the app is running in a browser or not, or even combine platform and web properties to have specific UI for your MACOS or Windows desktop apps.