@AppStorage lässt sich nicht animieren

Der Umschalter stand in einem `withAnimation`, und trotzdem sprang die Leiste
von einer Stellung in die andere. `@AppStorage` schreibt in die
Voreinstellungen und meldet die Änderung erst danach zurück — sie kommt also
außerhalb der Animation an, und die Animation hat nichts, woran sie sich
festhalten könnte.

Jetzt führt ein Zustand dieser Ansicht, und gespeichert wird hinterher. Die
Bindung an die Leisten bringt die Animation gleich mit.

Nachgesehen, nicht vermutet: mit versuchsweise zwei Sekunden Dauer und einer
Serienaufnahme von außen ist der Zwischenzustand fotografiert — Seitenleiste
halb nach links draußen, Leiste oben im Einblenden, Inhalt auf dem Weg. Danach
zurück auf knappe 0,32 Sekunden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-13 21:27:03 +02:00
co-authored by Claude Opus 5
parent 9a5412dc5d
commit 5b2d902cd9
2 changed files with 23 additions and 8 deletions
@@ -178,7 +178,7 @@ struct FlixySidebar: View {
if !isEditing {
Button {
withAnimation(.snappy(duration: 0.25)) { placement = .top }
placement = .top
} label: {
Image(systemName: "rectangle.topthird.inset.filled")
.font(.flixyRowHeader)
@@ -337,7 +337,7 @@ struct FlixyTopBar: View {
var body: some View {
HStack(spacing: FlixySpacing.tight) {
Button {
withAnimation(.snappy(duration: 0.25)) { placement = .sidebar }
placement = .sidebar
} label: {
Image(systemName: "sidebar.leading")
.font(.flixyBody)
+21 -6
View File
@@ -36,12 +36,25 @@ struct RootView: View {
@AppStorage("flixy.navigation.customization")
private var customization = TabViewCustomization()
/// Ob die Navigation an der Seite oder oben sitzt.
/// Ob die Navigation an der Seite oder oben sitzt — gespeichert.
///
/// Gespeichert, weil die Wahl dem Nutzer gehört und den Neustart
/// überleben muss.
/// Die Wahl gehört dem Nutzer und muss den Neustart überleben.
@AppStorage("flixy.navigation.placement")
private var placement: NavigationPlacement = .sidebar
private var storedPlacement: NavigationPlacement = .sidebar
/// Dieselbe Wahl, aber als Zustand dieser Ansicht.
///
/// Der Umweg ist nötig, damit das Umschalten überhaupt zu sehen ist:
/// `@AppStorage` schreibt in die Voreinstellungen und meldet die Änderung
/// erst danach zurück. Sie kommt also außerhalb der Animation an, und die
/// Leiste sprang von einer Stellung in die andere, statt zu wandern.
///
/// Hier ändert sich der Zustand sofort und im selben Zug; gespeichert wird
/// hinterher.
@State private var placement: NavigationPlacement = .sidebar
/// Wie die Leiste umzieht. Kurz, aber sichtbar.
private static let placementAnimation: Animation = .snappy(duration: 0.32)
/// Was der Nutzer an der Navigation umgestellt hat: Reihenfolge und was
/// überhaupt dastehen soll.
@@ -311,6 +324,8 @@ struct RootView: View {
#endif
}
.miniPlayer(player, isVisible: playback.presentation == .mini)
.onAppear { placement = storedPlacement }
.onChange(of: placement) { _, new in storedPlacement = new }
}
@ViewBuilder
@@ -320,7 +335,7 @@ struct RootView: View {
FlixySidebar(
groups: navigationGroups,
selection: $selection,
placement: $placement,
placement: $placement.animation(Self.placementAnimation),
layout: navigationLayout
)
// Sie kommt von der Seite herein und geht dorthin zurück. Ohne das
@@ -337,7 +352,7 @@ struct RootView: View {
FlixyTopBar(
groups: navigationGroups.map(visible),
selection: $selection,
placement: $placement
placement: $placement.animation(Self.placementAnimation)
)
Spacer(minLength: 0)
}