Safe areas

Cette page n'est pas encore traduite : la voici en anglais.

Sur cette page

A phone's screen has a notch or a punch hole, rounded corners, a status bar and a home indicator; a TV may crop the edges of the picture. The safe area is the part of the window clear of all of them. Aurore draws edge to edge: backgrounds fill the whole window, and the views that hold text and controls keep clear of the edges the safe area takes. Nothing to do in an app built on AppletFrame (or TabFrame, Cadran's frames): the frame does it.

What reports it

Platform The safe area
Android The system bars, the display cutout and the rounded corners over the SDL surface (PlatformUtils.getSafeAreaInsets, through JNI): WindowInsets of the bars and the cutout from Android 11, the system window insets and DisplayCutout before, nothing before Android 6. A rounded corner of radius r keeps r (1 − 1/√2) from both its edges (a rectangle's corner set in that far stays inside it). The keyboard is not part of it
iOS, tvOS UIWindow.safeAreaInsets (under SDL3, through SDL_GetWindowSafeArea, which reads it): the notch, the rounded corners, the home indicator; on tvOS, the TV's safe area
Desktops, Switch, PS4, PS Vita, New 3DS, a browser Nothing: zero, unless set (below)

The platform says it in the unit of the window's size (points on iOS, pixels on Android) through Platform::getSafeAreaInsets(). Application::getSafeArea() has it in layout units, whole ones, never more than a third of the window from an edge, and never less than the overscan margin.

It is read again when the window changes size, and on Android and iOS when the window is shown or comes back, and when the display turns (a turn of 180 degrees keeps the size and moves the notch to the other side), and under SDL3 when SDL says it changed: then once more 300 ms later, when the system has laid the window out. A change lays the views out again and fires Application::getSafeAreaChangedEvent() with the new insets. A platform of an app's own calls Application::updateSafeArea() when its safe area may have changed.

On a desktop, and a TV

AURORE_SAFE_AREA shows a phone's safe area on the desktop, in a build with AURORE_DEV_TOOLS (environment.md): AURORE_SAFE_AREA=47,0,34,0 (an iPhone held upright: top, right, bottom, left), AURORE_SAFE_AREA=0,48 (a notch on either side), AURORE_SAFE_AREA=30 (every edge), in the window's unit as a CSS padding is written. In code, Application::setSafeAreaOverride(&insets) does the same (nullptr goes back to the platform's).

Application::setOverscan(fraction) keeps every edge at least that fraction of the window clear: 0.05 is a TV's title safe area (5 %), for a setting of an app on a console or a TV box plugged into a set that crops the picture. 0 by default, at most 0.25.

In the layout

Box::setSafeArea(edges), safeArea="…" in XML, says which edges of a box keep clear of the safe area: there, the safe area is added to the box's padding, so the box's children move in while its background still reaches the window's edge.

Value Edges
auto (the default) none, but all of them for the content view of an activity
none none
top, right, bottom, left that one; joined with \| (top\|bottom), commas or spaces
vertical, horizontal, all top and bottom, left and right, every edge
<aurore:Box axis="column" safeArea="none" backgroundColor="@theme/aurore/background">
    <!-- a bar at the top: its colour up to the window's edge, its text below the notch -->
    <aurore:Box height="60" boxSizing="contentBox" safeArea="top|horizontal"
        backgroundColor="@theme/aurore/accent">
        <aurore:Label text="Title"/>
    </aurore:Box>
    <aurore:ScrollingFrame grow="1" safeArea="horizontal|bottom">
        …
    </aurore:ScrollingFrame>
</aurore:Box>

The rules:

  • Once on each path. A box that keeps clear of an edge does it for the views in it: they take the safe area no more. A box that keeps clear of none (none, or auto below the content view) lets them. So the content view of an activity keeps clear of every edge by default (auto), and the views in it do nothing; give it safeArea="none" to go edge to edge, and set the edges on the views at the window's edges.
  • The window's safe area. The inset added is the window's, whatever the box's place: set the edges of boxes that touch those edges of the window.
  • Fixed sizes. A box with a fixed height is that high with the safe area in it, its content squeezed. boxSizing="contentBox" makes it grow by the safe area instead, as a header does.
  • Your own padding. getPaddingTop() and the others give the box's own padding, and setPadding…() set it: the safe area stays added to it. getSafeAreaPadding() gives what is added now.
  • Absolute views. A view positioned absolutely (positionType="absolute") ignores its parent's padding, the safe area's too: place it from Application::getSafeArea().

Since nothing focusable lies in a box's padding, nothing can be focused or tapped under the insets, unless placed there absolutely.

The frames

An AppletFrame (and so a TabFrame, a Cadran screen) keeps clear of the safe area itself, edge to edge:

  • the frame keeps clear of the left and the right: its header, content and footer move in, the app's background behind them;
  • the header (content-box) grows by the top inset: its backdrop reaches the top of the window, its title and tools sit below the notch;
  • the footer (content-box) grows by the bottom inset, its hints above the home indicator;
  • with the header or the footer hidden (headerHidden, setHeaderVisibility), the frame keeps clear of that edge for the content;
  • the content takes nothing more: a frame inside it (a TabFrame in an AppletFrame) does nothing again.

setSafeArea() on a frame (or safeArea on its XML) replaces this: the frame then keeps clear of the edges it is given, its header and footer of nothing more.

The toasts (Application::notify) keep clear of the top and the right; a dialog, a dropdown or an action sheet is the content view of its activity: all its edges.

Testing it

Harness::setSafeArea(insets) has the harness' platform report a safe area (framebuffer pixels) and lays the screen out again; tests/demo_tests.cpp checks the demo's frame, a dialog and XML layouts with one, and their screenshots (safe_area_main_screen, safe_area_xml).

On a device, the safe area is logged when it changes (Safe area: top …).

Modifier cette page sur GitHub