Die Einstellungen lagen hinter der Leiste

Ein Sicherheitsrand je Bildschirm wandert nicht in einen geschobenen Bildschirm
mit. Die Einstellungen schieben ihre Unterseiten über gewöhnliche Verweise, und
dort fehlte er: die Beschriftungen lagen hinter der Seitenleiste und wurden von
der Maske abgeschnitten — zu sehen waren nur die rechtsbündigen Werte.

Der Platz für die Leiste ist jetzt ein echter Rand am ganzen TabView. Der gilt
für alles, was darin aufgeht.

Dazu: der Aufmacher nimmt zweiundachtzig statt hundert Prozent der Höhe. Über
die ganze Höhe sah er aus wie die einzige Seite der App — von den Reihen war
ohne Scrollen nichts zu sehen. So lugt die erste gerade herein.

Und das Umschalten zwischen Seite und oben hat eine Bewegung: die Leiste kommt
von der Seite beziehungsweise von oben herein und geht dorthin zurück. Die
Überlagerung behält dabei ihre Ausrichtung — wechselte sie mit, sprang die
Leiste im Übergang an die neue Ecke, statt dorthin zu wandern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-13 20:44:20 +02:00
co-authored by Claude Opus 5
parent ab0adef8d4
commit 9a5412dc5d
3 changed files with 61 additions and 16 deletions
+5 -3
View File
@@ -88,12 +88,14 @@ struct HeroCarousel: View {
// Die Höhe: fast das ganze Fenster.
//
// Ein Aufmacher, der nur ein Drittel hoch ist, sieht aus wie ein
// breites Vorschaubild. So hoch wie die Seitenleiste soll er sein,
// und die ist so hoch wie das Fenster.
// breites Vorschaubild — einer über die ganze Höhe dagegen wie die
// einzige Seite der App: von den Reihen war nichts mehr zu sehen,
// ohne zu scrollen. Zweiundachtzig Prozent lassen die erste Reihe
// gerade hereinlugen, und damit weiß man, dass es weitergeht.
//
// Auf einem schmalen Gerät nicht: dort ist der Aufmacher hochkant
// und rechnet sich seine Höhe aus der Breite aus.
.modifier(HeroHeight(fraction: sizeClass == .compact ? nil : 1))
.modifier(HeroHeight(fraction: sizeClass == .compact ? nil : 0.82))
// **Kein** Seitenverhältnis hier: der Aufmacher bringt sein
// eigenes mit, und eines darüber legte ihn auf die Breite des
// Inhaltsbereichs fest. Weil er nach links unter die Seitenleiste
+28 -13
View File
@@ -285,9 +285,22 @@ struct RootView: View {
#if os(iOS)
if sizeClass == .regular {
tabs
// Der Platz für die Leiste: als **echter** Rand am ganzen
// TabView, nicht als Sicherheitsrand je Bildschirm.
//
// Ein Sicherheitsrand wandert nicht in einen geschobenen
// Bildschirm mit. Die Einstellungen schieben ihre
// Unterseiten über gewöhnliche Verweise, und dort fehlte
// er: die Beschriftungen lagen hinter der Leiste und waren
// von der Maske abgeschnitten. Ein Rand am TabView gilt
// für alles, was darin aufgeht.
.padding(chromeInsets)
.background { TabChromeSuppressor().frame(width: 0, height: 0) }
.mask(alignment: .topLeading) { chromeMask }
.overlay(alignment: placement == .sidebar ? .topLeading : .top) {
// Immer dieselbe Ausrichtung: wechselte sie mit der
// Stellung, sprang die Leiste im Übergang an die neue Ecke,
// statt dorthin zu wandern.
.overlay(alignment: .topLeading) {
chrome
}
} else {
@@ -310,6 +323,11 @@ struct RootView: View {
placement: $placement,
layout: navigationLayout
)
// Sie kommt von der Seite herein und geht dorthin zurück. Ohne das
// erschien sie schlagartig an ihrem Platz, und beim Umschalten war
// nicht zu sehen, dass dasselbe umgezogen ist.
.transition(.move(edge: .leading).combined(with: .opacity))
case .top:
// In der Mitte, und zwar erzwungen: die Leiste ist so breit wie
// ihr Inhalt, und eine Überlagerung richtet sie dann nicht
@@ -323,6 +341,7 @@ struct RootView: View {
)
Spacer(minLength: 0)
}
.transition(.move(edge: .top).combined(with: .opacity))
}
}
@@ -462,22 +481,18 @@ struct RootView: View {
/// ganze Witz: eine Reihe bleibt damit fensterbreit und schiebt ihre
/// Kacheln beim Wischen hinter die Leiste, stellt aber im Ruhezustand
/// keine dorthin. Mit einem gewöhnlichen Abstand endete sie an der Kante.
/// Sagt einem Bildschirm, wie weit er nach links ausbrechen darf.
///
/// Nur noch das: den Platz nimmt sich der Rand am TabView. Hier bleibt die
/// Angabe für den Aufmacher, der bewusst darüber hinausgreift.
@ViewBuilder
private func chromed<Content: View>(@ViewBuilder content: () -> Content) -> some View {
#if os(iOS)
let insets = sizeClass == .regular ? chromeInsets : EdgeInsets()
content()
.safeAreaPadding(insets)
// Wie weit der Aufmacher nach links ausbrechen darf: bis genau an
// die **Kante der Leiste**, nicht bis an den Fensterrand.
//
// Der Unterschied ist ein Streifen von zwölf Punkten, und der war
// deutlich zu sehen: die Leiste schwebt mit Abstand zum Rand, das
// Bild lief daran vorbei, und neben der Leiste stand ein heller
// Streifen Bild, den nichts abdeckte. Endet das Bild an ihrer
// Kante, sieht man es nur noch **durch** sie hindurch — und genau
// so soll es sein.
.environment(\.flixyChromeInset, max(insets.leading - FlixySidebar.margin, 0))
.environment(
\.flixyChromeInset,
sizeClass == .regular ? max(chromeInsets.leading - FlixySidebar.margin, 0) : 0
)
#else
content()
#endif