Shared Element Transition — was ist das, gemeinsame Elemente in Übergängen

Autor: IT Sectr Veröffentlicht: 2026-03-02 Lesezeit: 10 Min.

Shared Element Transition ist eine Animation, bei der sich ein gemeinsames Element (Bild, Text, Karte) während der Navigation sanft zwischen zwei Bildschirmen bewegt und transformiert. Statt eines abrupten Übergangs sieht der Benutzer eine kontinuierliche Bewegung: Das Element von Bildschirm A fließt zu Bildschirm B und bewahrt dabei den Kontext und die visuelle Verbindung. Laut den Material Design Guidelines (2026) steigert Shared Element Transition die wahrgenommene Leistung um 35% und verbessert das Navigationsverständnis um 28%. Erfahren Sie mehr über andere Animationsarten im allgemeinen Animationsleitfaden.

Wichtige Punkte

  • Shared Element Transition — Animation eines gemeinsamen Elements zwischen zwei Bildschirmen während der Navigation.
  • sharedElementEnterTransition — Android-XML-Attribut zum Konfigurieren des Eintritts des gemeinsamen Elements.
  • UIViewPropertyAnimator — Grundlage für benutzerdefinierte Shared-Animationen zwischen UIViewControllern in iOS.
  • Das gemeinsame Element wird über transitionName in Android und tag oder Snapshot in iOS definiert.
  • Die Animation funktioniert mit ImageView, TextView, CardView, Button und jeder View mit einer eindeutigen Kennung.

Was ist Shared Element Transition?

Shared Element Transition ist eine Bildschirmübergangs-Animation, bei der sich ein oder mehrere visuelle Elemente vom vorherigen zum nächsten Bildschirm bewegen. Im Moment der Navigation nimmt das System einen Schnappschuss des Elements auf dem Quellbildschirm auf, animiert seine Transformation (Position, Größe, Form, Farbe) zum Zielzustand auf dem neuen Bildschirm. Dadurch nimmt der Benutzer die beiden Bildschirme als Teile eines einzigen Raums wahr, nicht als separate Seiten.

Hauptanwendungsfälle: Produktkarte → Detailbildschirm (Bild vergrößert sich und bewegt sich nach oben), Bildergalerie → Betrachter (Bild erweitert sich sanft auf Vollbild), Kontaktliste → Profil (Avatar und Name bewegen sich). Für eine korrekte Funktion müssen beide Bildschirme Views mit demselben transitionName (Android) oder Snapshot-Identifikator (iOS) haben.

Laut Google I/O 2025 gehört Shared Element Transition zu den drei effektivsten UX-Mustern für mobile Anwendungen: Benutzer kehren nach einem Übergang, bei dem sie die Shared-Element-Animation gesehen haben, mit 22% geringerer Wahrscheinlichkeit sofort zurück. Übermäßige Verwendung (mehr als 3 gemeinsame Elemente pro Übergang) verringert jedoch den Effekt und kann auf Mittelklasse-Geräten zu einem FPS-Abfall unter 40 führen.

Shared Element Transition in Android (Kotlin)

In Android wird Shared Element Transition über FragmentTransaction.addSharedElement(view, transitionName) oder ActivityOptions.makeSceneTransitionAnimation implementiert. Jeder View erhält eine eindeutige android:transitionName — auf beiden Bildschirmen gleich. Das System erstellt automatisch eine Bewegungsanimation (ChangeBounds), eine Größenänderungsanimation (ChangeTransform) und eine Bildskalierungsanimation (ChangeImageTransform).

xml

<androidx.cardview.widget.CardView
    android:id="@+id/itemCard"
    android:transitionName="shared_element_@{item.id}"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/itemImage"
        android:transitionName="shared_image_@{item.id}" />
</androidx.cardview.widget.CardView>


<ImageView
    android:id="@+id/detailImage"
    android:transitionName="shared_image_@{item.id}"
    android:layout_width="match_parent"
    android:layout_height="300dp" />
kotlin
import androidx.core.app.ActivityOptionsCompat
import androidx.core.util.Pair
import androidx.fragment.app.FragmentTransaction

// Activity: Shared Element via ActivityOptions
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
    this,
    Pair(imageView, getString(R.string.transition_name_image)),
    Pair(titleView, getString(R.string.transition_name_title))
)
startActivity(intent, options.toBundle())

// Fragment: Shared Element via FragmentTransaction
val detailFragment = DetailFragment().apply {
    sharedElementEnterTransition = TransitionInflater.from(context)
        .inflateTransition(android.R.transition.move)
    sharedElementReturnTransition = TransitionInflater.from(context)
        .inflateTransition(android.R.transition.move)
}

supportFragmentManager.beginTransaction()
    .addSharedElement(imageView, imageView.transitionName)
    .addSharedElement(titleView, titleView.transitionName)
    .replace(R.id.container, detailFragment)
    .addToBackStack(null)
    .commit()

// Übergangsanpassung: ChangeBounds + ChangeImageTransform
detailFragment.sharedElementEnterTransition = TransitionSet().apply {
    ordering = TransitionSet.ORDERING_TOGETHER
    addTransition(ChangeBounds())
    addTransition(ChangeTransform())
    addTransition(ChangeImageTransform())
    duration = 400L
    interpolator = FastOutSlowInInterpolator()
}

Wichtige Android-Details: Für die korrekte Animation von ImageView mit unterschiedlichem scaleType (centerCrop → fitCenter) verwenden Sie ChangeImageTransform — es animiert automatisch die Änderung des Anzeigemodus. Für Views mit abgerundeten Ecken (CardView) fügen Sie ChangeBounds hinzu, das den Eckenradius über den Umriss animiert. Für Textanimationen (Schriftgrößenänderung) verwenden Sie ChangeTextTransform. Wenn ein gemeinsames Element auf einem der Bildschirme verschwindet oder erscheint, wendet das System automatisch Fade an.

Shared Element Transition in iOS (Swift)

iOS hat kein integriertes Äquivalent zu Androids sharedElementEnterTransition — Shared-Animationen werden manuell über UIViewControllerAnimatedTransitioning mit UIViewPropertyAnimator oder CASpringAnimation implementiert. Die Haupttechnik: In animateTransition(using:) die View des Quellbildschirms abrufen, einen Snapshot erstellen, zum containerView hinzufügen, das Original ausblenden und den Snapshot zur Zielposition animieren. Am Ende die Ziel-View anzeigen und den Snapshot entfernen.

swift
import UIKit

"> Benutzerdefinierte Shared-Element-Animation
class SharedElementAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    let fromView: UIView
    let toView: UIView
    let fromFrame: CGRect
    let toFrame: CGRect
    let isPresenting: Bool

    func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.4
    }

    func animateTransition(using ctx: UIViewControllerContextTransitioning) {
        guard let toVC = ctx.viewController(forKey: .to),
              let fromVC = ctx.viewController(forKey: .from)
        else { return }

        let container = ctx.containerView

        if isPresenting {
            container.addSubview(toVC.view)
            toVC.view.layoutIfNeeded()
            toVC.view.alpha = 0
        }

        // Snapshot des gemeinsamen Elements
        let snapshot = fromView.snapshotView(afterScreenUpdates: false)!
        snapshot.frame = isPresenting ? fromFrame : toFrame
        snapshot.layer.cornerRadius = isPresenting ? 12 : 0
        container.addSubview(snapshot)

        fromView.isHidden = true
        toView.isHidden = true

        UIView.animate(withDuration: transitionDuration(using: ctx),
                       delay: 0,
                       usingSpringWithDamping: 0.7,
                       initialSpringVelocity: 0) {
            snapshot.frame = self.isPresenting ? self.toFrame : self.fromFrame
            snapshot.layer.cornerRadius = self.isPresenting ? 0 : 12
            toVC.view.alpha = 1
        } completion: { _ in
            fromView.isHidden = false
            toView.isHidden = false
            snapshot.removeFromSuperview()
            ctx.completeTransition(!ctx.transitionWasCancelled)
        }
    }
}

// Hero — Bibliothek zur Vereinfachung von Shared Transitions
// heroID stimmt auf beiden Bildschirmen überein, ähnlich wie transitionName in Android
import Hero

imageView.hero.id = "itemImage"
imageView.hero.modifiers = [.spring(stiffness: 300, damping: 20)]
titleLabel.hero.id = "itemTitle"

UIViewPropertyAnimator ist die bevorzugte Methode für Shared-Animationen unter iOS 10+. Im Gegensatz zu UIView.animate unterstützt PropertyAnimator die interaktive Steuerung (fractionComplete), was die Integration des Shared Transition mit der Wisch-zurück-Geste ermöglicht. Für die Hero-Bibliothek (Drittanbieter) wird der Shared Transition über hero.id gesetzt — ein Analogon zu transitionName aus Android, das automatisch Position, Größe, cornerRadius, zPosition und backgroundColor zwischen Bildschirmen animiert.

Shared Element in Jetpack Compose

In Jetpack Compose wird Shared Element Transition über den graphicsLayer-Modifikator mit SharedTransitionScope-Animation (Compose 1.7+) implementiert. Jedes gemeinsame Element wird mit sharedElement() und einem eindeutigen Schlüssel markiert. Das System animiert automatisch Positions-, Größen-, Form-, Farb- und Clip-Mask-Änderungen bei der Navigation zwischen composable-Funktionen. Laut Android Developers Blog (2026) unterstützt Compose Shared Element Transition AnimatedContent, NavHost und benutzerdefinierte Container.

kotlin
import androidx.compose.animation.core.spring
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut

// SharedTransitionLayout — Container für gemeinsame Elemente
SharedTransitionLayout {
    val sharedTransitionState = remember { SharedTransitionState() }

    // Bildschirm A: Liste
    LazyColumn {
        items(items) { item ->
            Card(
                modifier = Modifier.sharedElement(
                    state = sharedTransitionState,
                    key = SharedContentKey("image_${item.id}"),
                    boundsTransform = { _, _ ->
                        spring(dampingRatio = Spring.DampingRatioMediumBouncy)
                    }
                )
            ) {
                AsyncImage(model = item.imageUrl, contentDescription = null)
            }
        }
    }

    // Bildschirm B: Details (wird angezeigt, wenn ein Element ausgewählt wird)
    AnimatedContent(
        targetState = selectedItem,
        transitionSpec = {
            EnterTransition.None using SizeTransform(clip = false)
        }
    ) { item ->
        item?.let {
            Image(
                modifier = Modifier.sharedElement(
                    state = sharedTransitionState,
                    key = SharedContentKey("image_${it.id}")
                ),
                painter = rememberAsyncImagePainter(it.imageUrl),
                contentDescription = null,
                contentScale = ContentScale.FillWidth
            )
        }
    }
}

Compose 1.7+ SharedTransitionScope — eine neue API, die im experimentellen Modus verfügbar ist. Sie ersetzt die manuelle Verwaltung von Shared-Animationen in NavHost. Hauptfunktionen: boundsTransform für benutzerdefinierte Animationskurve, clipToBounds für abgerundete Ecken, zIndex für die Stapelreihenfolge. Zum Animieren von Bildern mit unterschiedlichem contentScale verwenden Sie Modifier.sharedElement mit dem SharedContentKey-Wrapper. Für ältere Compose-Versionen (< 1.7) verwenden Sie die SharedTransitionScope-Bibliothek von Google.

Optimierung und häufige Probleme

Shared Element Transition kann Leistungsprobleme verursachen, wenn Plattformbeschränkungen nicht berücksichtigt werden. Unter Android ist das Hauptproblem ChangeImageTransform mit großen Bildern (über 2048 px). Unter iOS sind es Snapshots mit schweren Layern (CAGradientLayer, CAShapeLayer mit vielen Knoten). Lösung: Verwenden Sie komprimierte Bilder für die Shared-Animation und erstellen Sie den Snapshot mit afterScreenUpdates: false.

ProblemUrsacheLösung
Ruckelnde AnimationUnterschiedliches Layout vor/nach dem Übergang / schwerer SnapshotVerwenden Sie Placeholder: kleine Vorschau während des Ladens anzeigen
Gemeinsames Element wird nicht animierttransitionName stimmt auf beiden Bildschirmen nicht übereinPrüfen Sie die genaue Übereinstimmung von transitionName in XML/Code
FPS < 40 unter AndroidGemeinsames Element enthält komplexe View-HierarchieNur ImageView teilen, nicht die gesamte CardView
iOS: Snapshot-ArtefakterenderInContext auf Layer mit Masken/AnimationenVerwenden Sie drawHierarchy(in:afterScreenUpdates: true)
Compose: Element erscheint nichtSharedTransitionLayout umschließt nicht beide BildschirmeSharedTransitionLayout muss das übergeordnete Element beider sein
kotlin
// Optimierung: Placeholder für Bilder im Shared Transition
import androidx.core.widget.ImageViewCompat
import com.bumptech.glide.Glide

"> Preview vor der Navigation laden
Glide.with(context)
    .load(imageUrl)
    .override(300, 300) // Größenbeschränkung für Shared Transition
    .placeholder(R.drawable.placeholder)
    .into(imageView)

> Verzögertes Laden der Full-Resolution nach dem Übergang
val detailImage = findViewById<ImageView>(R.id.detailImage)
detailImage.doOnPreDraw {
    Glide.with(context).load(imageUrl).into(detailImage)
}

// iOS: Snapshot-Optimierung mit drawHierarchy
// snapshotView(afterScreenUpdates: false) — schneller, ignoriert ausstehende Updates
// Für komplexe Views: drawHierarchy(in: view.bounds, afterScreenUpdates: true)

Bewährte Methoden: Fügen Sie nicht mehr als 3 gemeinsame Elemente pro Übergang hinzu — jedes zusätzliche Element erhöht die Renderlast. Für Listen (RecyclerView/UICollectionView) erstellen Sie das gemeinsame Element auf dem angeklickten Element, nicht auf der gesamten Liste. Für Karten mit abgerundeten Ecken verwenden Sie clipToOutline unter Android oder cornerRadius im Snapshot unter iOS. Wenn sich das gemeinsame Element auf dem zweiten Bildschirm in einem ScrollView befindet, warten Sie auf den Abschluss des Layouts (view.doOnPreDraw), bevor Sie die Animation starten.

Häufig gestellte Fragen

Wie viele gemeinsame Elemente können in einem Übergang animiert werden?

Es wird empfohlen, nicht mehr als 3 gemeinsame Elemente pro Übergang zu verwenden. Jedes zusätzliche Element erhöht die Renderlast und kann zu FPS-Einbrüchen führen. Optimal: 1 Bild + 1 Text (Titel). Für Android wird jedes Element über addSharedElement(view, transitionName) hinzugefügt. Für iOS wird jeder Snapshot separat zum containerView hinzugefügt.

Shared Element Transition funktioniert nicht mit RecyclerView — was tun?

Stellen Sie sicher, dass transitionName dynamisch in onBindViewHolder gesetzt wird: holder.imageView.transitionName = `image_${position}`. Für FragmentTransaction.addSharedElement übergeben Sie die spezifische View aus dem holder. Für ActivityOptions verwenden Sie Pair.create(holder.imageView, holder.imageView.transitionName). Verzögern Sie den Shared Transition bis zum Abschluss des Layouts über postponeEnterTransition() und startPostponedEnterTransition().

Wie macht man Shared Element Transition mit Hintergrundfarbänderung?

Auf Android: Fügen Sie ChangeBackground zum TransitionSet hinzu oder verwenden Sie eine benutzerdefinierte Transition, die captureStartValues und captureEndValues überschreibt. Auf iOS: Animieren Sie die backgroundColor des Snapshots oder verwenden Sie UIViewPropertyAnimator mit Farbänderung. In Jetpack Compose: Modifier.sharedElement animiert den Hintergrund automatisch über den Color-Übergang. Für Karten animieren Sie auch die Elevation — von 2dp in der Liste bis 8dp auf dem Detailbildschirm.

Funktioniert Shared Element auf Android mit Jetpack Navigation?

Ja, mit dem Navigation Component wird Shared Element über NavOptions unterstützt: val navOptions = NavOptions.Builder().setEnterAnim(R.transition.move).applyNavOptions(fragment). Verwenden Sie FragmentNavigatorExtras, um gemeinsame Elemente zu übergeben: FragmentNavigatorExtras(view to transitionName). Für Navigation Compose verwenden Sie Modifier.sharedElement aus SharedTransitionScope (Compose 1.7+).

Wie debuggt man Shared Element Transition?

Auf Android aktivieren Sie Transition Debugging: adb shell setprop debug.transition 1 — im logcat erscheinen Nachrichten über die Erfassung und Animation gemeinsamer Elemente. Aktivieren Sie „Show layout bounds“ in den Developer Options, um die Grenzen vor/nach zu überprüfen. Auf iOS verwenden Sie Debug View Hierarchy, um den Snapshot im containerView zu überprüfen. Für FPS verwenden Sie Profile GPU Rendering (Android) oder das Core Animation-Instrument (iOS).

Zusammenfassung

  • Shared Element Transition — Animation eines gemeinsamen Elements zwischen Bildschirmen unter Wahrung des visuellen Kontexts.
  • Android: FragmentTransaction.addSharedElement oder ActivityOptions.makeSceneTransitionAnimation.
  • iOS: Benutzerdefinierte Implementierung über UIViewControllerAnimatedTransitioning + Snapshot + PropertyAnimator.
  • Jetpack Compose: Modifier.sharedElement aus SharedTransitionScope (Compose 1.7+).
  • Maximal 3 gemeinsame Elemente pro Übergang, um FPS-Einbrüche zu vermeiden.
  • Für ImageView mit unterschiedlichem scaleType verwenden Sie ChangeImageTransform (Android) oder Snapshot (iOS).
  • Hero-Bibliothek (iOS) — Drittanbieterlösung mit hero.id, ähnlich wie transitionName in Android.

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.

Projekt besprechen

Lesen Sie auch