Wichtige Erkenntnisse
Hero Animation ist eine UI-Animationstechnik, bei der ein gemeinsames Element nahtlos von einem Quellbildschirm zu einem Zielbildschirm wechselt und dabei seine Identität bewahrt. Der Name spiegelt die Metapher eines „Helden“ wider — eines Schlüsselelements, das einen skriptgesteuerten Übergang zwischen Bildschirmen durchläuft und die Aufmerksamkeit des Benutzers auf sich zieht. Im Gegensatz zu Standardübergängen unterbricht Hero Animation die visuelle Verbindung nicht: Der Benutzer sieht eine kontinuierliche Flugbahn des Elements, was das Verständnis der Navigationshierarchie verbessert.
Das Konzept der Hero Animation ist in Material Design als Empfehlung für Listen-Detail-Bildschirme, Galerien und Karten etabliert. Der Animationsalgorithmus besteht aus drei Phasen: Auf dem Quellbildschirm wird das Element hervorgehoben und in einer absoluten Position fixiert; während des Übergangs skaliert, bewegt und verändert es seine Form entsprechend dem Zielcontainer; auf dem endgültigen Bildschirm wird das Element in das neue Layout eingebettet. Laut Material Design 3 reduziert eine korrekt implementierte Helden-Animation die Anzahl der fehlerhaften „Zurück“-Tastendrücke um 22%.
In Flutter wird Hero Animation durch das Hero-Widget implementiert, das einen erforderlichen Parameter tag — einen eindeutigen Identifikator — annimmt. Flutter findet automatisch ein Paar von Hero-Widgets mit demselben Tag auf den Quell- und Zielrouten und startet die Animation. Das Hero-Widget erfordert keine manuelle Animationsverwaltung — das Framework berechnet unabhängig die Flugbahn und wendet die Transformation durch das interne FlightShuttle-Objekt an.
FlightShuttle ist eine unsichtbare „Fähre“, die im Moment des Übergangs eine Überlagerungskopie des Hero-Widgets erstellt, sie in einem absoluten Koordinatensystem positioniert und die Transformation (Skalierung, Verschiebung, Drehung) von der Anfangsposition zur Endposition animiert. Benutzerdefinierte Kurven können über die flightShuttleBuilder-Eigenschaft an FlightShuttle übergeben werden, was die Steuerung der Flugbahn ermöglicht: im Bogen fliegen, an Grenzen abprallen oder vor der Ankunft verlangsamen. In Flutter 3.16+ unterstützt Hero Animation unter Beibehaltung von clipRect und borderRadius, was den Effekt abgerundeter Karten ergibt, die sich in rechteckige Bildschirme verwandeln.
In SwiftUI ist das Äquivalent der Hero Animation der matchedGeometryEffect-Modifikator, der in iOS 14 eingeführt wurde. Er verbindet zwei Elemente über einen Identifikator (id) und einen Namespace. Im Gegensatz zu Flutter, wo Hero den Übergang automatisch abfängt, erfordert SwiftUI eine explizite Deklaration des Namespace und die Anwendung des Modifikators auf beide Szenenteile — Quelle und Ziel — innerhalb derselben Hierarchie oder über GeometryReader.
Die matchedGeometryEffect-Animation unterstützt die Transformation von Position, Größe, Drehung und Eckenradius. Für Geschmeidigkeit wird eine Animation in withAnimation angegeben. SwiftUI interpoliert Zwischenzustände automatisch basierend auf der Standardkurve easeInOut. In iOS 17+ wurde Unterstützung für matchedTransitionSource für TabView und NavigationStack hinzugefügt — ein Systemanalog der Hero Animation mit vordefinierter Flugbahn für Standardübergänge.
In Android wird Hero Animation als Shared Element Transition bezeichnet und durch ActivityOptions.makeSceneTransitionAnimation oder FragmentTransaction.addSharedElement implementiert. Jedes gemeinsame Element wird mit einem transitionName-Attribut in XML oder durch Code markiert, und Android übernimmt die Animation zwischen Aktivitäten. Ab Android 5.0 (API 21) wurden Übergänge Teil des Frameworks; davor mussten benutzerdefinierte Animationen mit ValueAnimator geschrieben werden.
In Jetpack Compose wird Shared Element Transition durch die Modifikatoren Modifier.sharedElement und Modifier.sharedBounds in Verbindung mit AnimatedContent oder SharedTransitionLayout (verfügbar seit Compose BOM 2024.01) implementiert. Im Gegensatz zum View-System zeichnet Compose Elemente träge neu, sodass das gemeinsame Element in CompositionLocal zwischengespeichert wird. Compose unterstützt auch Listen-zu-Detail-Animation mit Beibehaltung des scrollOffset — eine Schlüsselfähigkeit für Hero-Übergänge. Laut Google I/O 2024 ist Compose Shared Element Transition aufgrund der direkten RenderNode-Verwaltung 15% schneller als die View-Version.
Ein grundlegendes Beispiel von Hero Animation in Flutter: ein Thumbnail auf dem Listenbildschirm und ein Vollbild auf dem Detailbildschirm. Der Tag image-hero verbindet die beiden Widgets, und FlightShuttle animiert automatisch den Übergang von der Karte zum Vollbild.
import 'package:flutter/material.dart';
class ListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Hero(
tag: 'image-hero',
child: GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(
builder: (_) => DetailScreen(),
),
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://picsum.photos/200',
width: 100, height: 100,
fit: BoxFit.cover,
),
),
),
),
],
),
);
}
}
class DetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Detail')),
body: Center(
child: Hero(
tag: 'image-hero',
child: Image.network(
'https://picsum.photos/800',
width: 300, height: 400,
fit: BoxFit.cover,
),
),
),
);
}
}
Der entscheidende Punkt ist der gleiche Tag (image-hero) auf beiden Bildschirmen. Flutter gleicht Hero-Widgets während des Routenübergangs nach Tag ab. Wenn die Tags unterschiedlich sind, wird die Animation nicht gestartet — das Element erscheint einfach ohne Übergang auf dem neuen Bildschirm. Jeder Typ kann für den Tag verwendet werden, aber Strings sind die zuverlässigste Option.
Ein Beispiel von Hero Animation in SwiftUI mit NavigationStack. Der matchedGeometryEffect-Modifikator verbindet das Bild in der Liste und den Detailbildschirm über einen Namespace, und withAnimation löst einen nahtlosen Übergang aus.
import SwiftUI
struct HeroExampleView: View {
@Namespace private var heroNamespace
@State private var isDetailShown = false
var body: some View {
VStack {
if isDetailShown {
DetailView(namespace: heroNamespace)
.transition(.identity)
} else {
ListView(namespace: heroNamespace)
.transition(.identity)
}
}
.animation(Animation.easeInOut(duration: 0.4),
value: isDetailShown)
}
}
struct ListView: View {
let namespace: Namespace.ID
var body: some View {
Image("thumbnail")
.resizable()
.frame(width: 100, height: 100)
.cornerRadius(12)
.matchedGeometryEffect(id: "hero", in: namespace)
}
}
struct DetailView: View {
let namespace: Namespace.ID
var body: some View {
Image("thumbnail")
.resizable()
.frame(width: 300, height: 400)
.cornerRadius(0)
.matchedGeometryEffect(id: "hero", in: namespace)
}
}
@Namespace erstellt einen Namensraum für den matchedGeometryEffect-Identifikator. Beide Elemente verwenden dieselbe id („hero“) und einen gemeinsamen Namespace. Beim Umschalten von isDetailShown animiert SwiftUI die Transformation von Größe, Position und Eckenradius zwischen den beiden Ansichten und erzeugt den Heldeneffekt. Für einen standardmäßigen NavigationLink mit iOS 16+ verwenden Sie navigationTransition(.hero).
Ein Beispiel einer Shared Element Transition in Jetpack Compose mit SharedTransitionLayout. Der sharedElement-Modifikator animiert ein gemeinsames Element zwischen Bildschirmen während der Navigation.
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun HeroExample() {
SharedTransitionLayout {
var isDetail by remember { mutableStateOf(false) }
AnimatedContent(
targetState = isDetail,
transitionSpec = {
fadeIn() togetherWith fadeOut()
}
) { detail ->
if (detail) {
Box(
modifier = Modifier
.fillMaxSize()
.sharedElement(
state = rememberSharedContentState(key = "hero"),
animatedVisibilityScope = this
)
) {
AsyncImage(
model = "https://picsum.photos/800",
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
}
} else {
Box(
modifier = Modifier
.size(100.dp)
.sharedElement(
state = rememberSharedContentState(key = "hero"),
animatedVisibilityScope = this
)
) {
AsyncImage(
model = "https://picsum.photos/200",
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
}
}
}
}
}
Compose SharedTransitionLayout (Compose BOM 2024.01+) umschließt die Hierarchie, und der sharedElement-Modifikator mit dem Schlüssel „hero“ verbindet die Anfangs- und Endelemente. AnimatedContent schaltet den Zustand um, und Compose animiert automatisch Größe, Position und Form des Bildes. Ein wesentlicher Vorteil ist die Unterstützung von bounds- und clipBounds-Animation, die den Kartenabrundungseffekt während des Übergangs ermöglicht.
Häufig gestellte Fragen
Ja, Hero Animation ist auf beiden Plattformen verfügbar. iOS verwendet matchedGeometryEffect in SwiftUI oder UINavigationController.transitioningDelegate. Android verwendet ActivityOptions.makeSceneTransitionAnimation oder Shared Element Transition in Jetpack Compose mit Modifier.sharedElement. Flutter implementiert Hero Animation durch das Hero-Widget, das auf beiden Plattformen identisch funktioniert.
Ja, Hero Animation unterstützt mehrere gemeinsame Elemente. In Flutter geben Sie mehrere Hero-Widgets mit verschiedenen Tags an. In SwiftUI verwenden Sie matchedGeometryEffect mit verschiedenen Identifikatoren auf jedem Element. Alle Animationen laufen parallel — jedes Element reist auf seiner eigenen Flugbahn.
Die Leistung hängt von der Implementierung ab. Flutter FlightShuttle verarbeitet Bilder über RenderObject und erreicht 60fps. SwiftUI matchedGeometryEffect ist vektorisiert. Für große Bilder verwenden Sie precacheImage in Flutter oder prefetch in SwiftUI — dies beseitigt Verzögerungen beim ersten Übergang. Android Compose erfordert verzögertes Laden über AsyncImage.
Ein standardmäßiger Push-Übergang schiebt den gesamten Bildschirm und erzeugt die Illusion eines Kartenstapels. Hero Animation fixiert die visuelle Aufmerksamkeit auf einem einzelnen Element — der Benutzer sieht seine kontinuierliche Bewegung, was das Verständnis der Beziehung zwischen den Bildschirmen verbessert. Push eignet sich für hierarchische Navigation, Hero für die Hervorhebung von Inhalten.
Nein, Hero Animation ist mit integrierten Werkzeugen implementiert. In Flutter ist es das Hero-Widget aus dem Paket flutter/material.dart. In SwiftUI ist es der matchedGeometryEffect-Modifikator. In Android Jetpack Compose sind es SharedTransitionLayout und Modifier.sharedElement aus Standard-Compose. Zusätzliche Bibliotheken werden nur für nicht standardmäßige Flugbahnen oder komplexe Transformationen benötigt.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch