Der Aufmacher hellte beim Wechsel auf — zwei Verläufe ergeben keinen
Beim Wechsel im Karussell war der Verlauf nach unten für einen Moment
weg: das Bild stand bis unten hell da, und erst nach dem Übergang kam das
Abdunkeln zurück.
**Der Grund steckt in der Form der Überblendung.** Das Karussell legte
zwei vollständige Aufmacher übereinander und blendete den oberen ein. Nur
bringt jeder von beiden seinen eigenen Verlauf mit — und zwei
halbdurchsichtige Verläufe ergeben zusammen keinen ganzen.
Gemessen, an derselben Stelle im Bild, über einen auf sechs Sekunden
gestreckten Wechsel:
Ruhezustand 68 .. 75
Mitte des Wechsels 137 ← fast doppelt so hell
Zwei naheliegende Reparaturen habe ich davor versucht und verworfen,
weil die Messung sie widerlegt hat: dem weichenden Aufmacher die
Animation zu nehmen (wurde schlechter, 152) und beide Ebenen
gegenläufig zu blenden (brachte einen dunklen Einbruch auf 35 dazu).
Beide behandelten das Symptom, nicht die Form.
**Jetzt wechselt nur das Bild.** `HeroBanner` nimmt zusätzlich die
weichende Bildadresse entgegen und blendet **innen** über; Verlauf,
Schriftzug und Knöpfe liegen einmal darüber und ändern sich dabei nicht.
Damit kann der Verlauf gar nicht mehr schwächer werden — nicht weil es
jetzt richtig gerechnet wird, sondern weil es nur noch einen gibt.
Nachgemessen, derselbe Wechsel:
vorher 68 .. 154
jetzt 63 .. 75
Die Aufmacher-Ansicht behält dabei ihre Identität, statt je Titel eine
neue zu bekommen: eine neue hiesse Einfügen und Entfernen, und SwiftUI
blendete sie dann zusätzlich ein — noch eine Überblendung über der
gemeinten.
iOS und tvOS bauen, 476 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a665d79e6d
commit
63c664e5a9
@@ -18,6 +18,24 @@ public struct HeroBanner<Actions: View>: View {
|
||||
private let metadataContent: AnyView?
|
||||
private let summary: String?
|
||||
private let artworkURLs: [URL]
|
||||
/// Das Bild, das gerade verschwindet — nur für den Aufmacher mit Wechsel.
|
||||
///
|
||||
/// **Warum die Überblendung hier drin steckt und nicht darüber.** Das
|
||||
/// Karussell legte vorher zwei ganze Aufmacher übereinander und blendete
|
||||
/// den oberen ein. Jeder bringt seinen eigenen Verlauf nach unten mit —
|
||||
/// und zwei halbdurchsichtige Verläufe ergeben zusammen **keinen** ganzen.
|
||||
/// Gemessen an derselben Stelle: im Ruhezustand 68, in der Mitte des
|
||||
/// Wechsels 137. Sichtbar als ein Aufhellen genau dort, wo der Titel
|
||||
/// steht.
|
||||
///
|
||||
/// Jetzt wechselt nur das **Bild**; Verlauf und Text liegen einmal
|
||||
/// darüber und ändern sich nicht. Damit kann der Verlauf gar nicht mehr
|
||||
/// schwächer werden.
|
||||
private let outgoingArtworkURLs: [URL]
|
||||
/// Wie weit das neue Bild schon deckt: 0 beim Beginn, 1 am Ende.
|
||||
private let crossfade: CGFloat
|
||||
/// Wie weit das neue Bild dabei hereinrutscht.
|
||||
private let incomingOffset: CGFloat
|
||||
/// Der freigestellte Schriftzug des Films. Steht er zur Verfügung, tritt
|
||||
/// er an die Stelle des gesetzten Titels — „Harry Potter" in seiner
|
||||
/// eigenen Schrift ist wiedererkennbar, eine Systemschrift nicht.
|
||||
@@ -35,6 +53,9 @@ public struct HeroBanner<Actions: View>: View {
|
||||
metadataContent: AnyView? = nil,
|
||||
summary: String? = nil,
|
||||
artworkURLs: [URL],
|
||||
outgoingArtworkURLs: [URL] = [],
|
||||
crossfade: CGFloat = 1,
|
||||
incomingOffset: CGFloat = 0,
|
||||
logoURL: URL? = nil,
|
||||
// 16:9, weil Plex genau das als `art` liefert. Vorher stand hier
|
||||
// 3:4 — mit `scaledToFill` wurde das Bild dadurch links und rechts
|
||||
@@ -49,6 +70,9 @@ public struct HeroBanner<Actions: View>: View {
|
||||
self.metadataContent = metadataContent
|
||||
self.summary = summary
|
||||
self.artworkURLs = artworkURLs
|
||||
self.outgoingArtworkURLs = outgoingArtworkURLs
|
||||
self.crossfade = crossfade
|
||||
self.incomingOffset = incomingOffset
|
||||
self.logoURL = logoURL
|
||||
self.aspectRatio = aspectRatio
|
||||
self.fillsAvailableSpace = fillsAvailableSpace
|
||||
@@ -67,6 +91,24 @@ public struct HeroBanner<Actions: View>: View {
|
||||
min(max(width / 834, 1), 1.7)
|
||||
}
|
||||
|
||||
/// Das Bild — und, solange gewechselt wird, das vorige darunter.
|
||||
///
|
||||
/// Ohne Wechsel ist es genau ein `FlixyArtwork` wie zuvor: die zweite
|
||||
/// Ebene entsteht nur, wenn jemand eine vorige Adresse mitgibt.
|
||||
@ViewBuilder
|
||||
private var bild: some View {
|
||||
if outgoingArtworkURLs.isEmpty {
|
||||
FlixyArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace)
|
||||
} else {
|
||||
ZStack {
|
||||
FlixyArtwork(urls: outgoingArtworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace)
|
||||
FlixyArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace)
|
||||
.opacity(crossfade)
|
||||
.offset(x: incomingOffset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Schriftzug, wenn vorhanden — sonst gesetzter Titel.
|
||||
///
|
||||
/// Geladen wird über `ArtworkLoader`, **nicht** über `AsyncImage`. Der
|
||||
@@ -127,7 +169,7 @@ public struct HeroBanner<Actions: View>: View {
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
FlixyArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace)
|
||||
bild
|
||||
.overlay(alignment: .bottom) {
|
||||
// Der Verlauf endet in der Hintergrundfarbe der Seite, nicht in
|
||||
// Schwarz: sonst entsteht genau dort, wo der Aufmacher in die
|
||||
|
||||
Reference in New Issue
Block a user