Shared Element Transition — mi ez, közös elemek az átmenetekben

Szerző: IT Sectr Megjelenés: 2026-03-02 Olvasási idő: 10 perc

Shared Element Transition — egy olyan animáció, amelyben egy közös elem (kép, szöveg, kártya) simán mozog és transzformálódik két képernyő között navigáció közben. Éles átmenet helyett a felhasználó folyamatos mozgást lát: az elem az A képernyőről «átfolyik» a B képernyőre, megtartva a kontextust és a vizuális kapcsolatot. A Material Design Guidelines (2026) szerint a Shared Element Transition 35%-kal növeli az észlelt teljesítményt és 28%-kal javítja a navigáció megértését. További animációs típusokról olvasson az általános animációs útmutatóban.

Főbb pontok

  • Shared Element Transition — egy közös elem animációja két képernyő között navigáció során.
  • sharedElementEnterTransition — Android XML attribútum a közös elem belépésének konfigurálásához.
  • UIViewPropertyAnimator — az egyedi megosztott animációk alapja UIViewController-ek között iOS-ben.
  • A közös elem a transitionName segítségével van beállítva Androidban és tag vagy snapshot segítségével iOS-ben.
  • Az animáció működik ImageView, TextView, CardView, Button és bármely View egyedi azonosítóval.

Mi az a Shared Element Transition?

Shared Element Transition — egy képernyőváltó animáció, amelyben egy vagy több vizuális elem «átköltözik» az előző képernyőről a következőre. A navigáció pillanatában a rendszer snapshotot készít az elemről a forrásképernyőn, animálja annak transzformációját (pozíció, méret, forma, szín) a célállapotba az új képernyőn. Ennek eredményeként a felhasználó a két képernyőt egy egységes tér részeiként érzékeli, nem pedig különálló oldalakként.

Fő használati forgatókönyvek: termékkártya → részletes képernyő (a kép megnő és felülre kerül), képgaléria → nézet (a kép simán teljes képernyőre nyílik), névjegy lista → profil (az avatar és a név elmozdul). A helyes működéshez mindkét képernyőnek rendelkeznie kell egy View-val azonos transitionName (Android) vagy snapshot azonosítóval (iOS).

A Google I/O 2025 szerint a Shared Element Transition a három leghatékonyabb UX minta egyike mobil alkalmazásokhoz: a felhasználók 22%-kal ritkábban térnek vissza azonnal az átmenet után, ha látták a közös elem animációját. A túlzott használat (átmenetenként 3-nál több megosztott elem) azonban csökkenti a hatást, és a középkategóriás eszközökön 40 alá csökkentheti az FPS-t.

Shared Element Transition Androidban (Kotlin)

Androidban a Shared Element Transition a FragmentTransaction.addSharedElement(view, transitionName) vagy ActivityOptions.makeSceneTransitionAnimation segítségével valósítható meg. Minden View egyedi android:transitionName-t kap — ugyanazt mindkét képernyőn. A rendszer automatikusan létrehozza a mozgás (ChangeBounds), méretváltozás (ChangeTransform) és képméretezés (ChangeImageTransform) animációját.

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 ActivityOptions segítségével
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 FragmentTransaction segítségével
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()

// Átmenet testreszabása: ChangeBounds + ChangeImageTransform
detailFragment.sharedElementEnterTransition = TransitionSet().apply {
    ordering = TransitionSet.ORDERING_TOGETHER
    addTransition(ChangeBounds())
    addTransition(ChangeTransform())
    addTransition(ChangeImageTransform())
    duration = 400L
    interpolator = FastOutSlowInInterpolator()
}

Fontos Android részletek: a különböző scaleType (centerCrop → fitCenter) ImageView helyes animálásához használja a ChangeImageTransform-ot — ez automatikusan animálja a megjelenítési mód változását. Lekerekített sarkú View (CardView) esetén adja hozzá a ChangeBounds-ot, amely a sarok sugarát animálja outline segítségével. Szöveg animálásához (betűméret változása) használja a ChangeTextTransform-ot. Ha a megosztott elem eltűnik vagy megjelenik az egyik képernyőn — a rendszer automatikusan Fade-et alkalmaz.

Shared Element Transition iOS-ben (Swift)

Az iOS-ben nincs beépített megfelelője az Android sharedElementEnterTransition-jének — a megosztott animációk manuálisan valósíthatók meg a UIViewControllerAnimatedTransitioning segítségével UIViewPropertyAnimator vagy CASpringAnimation használatával. Fő technika: az animateTransition(using:) metódusban vegye a forrásképernyő View-ját, készítsen róla snapshotot, adja hozzá a containerView-hez, rejtse el az eredetit, és animálja a snapshotot a célpozícióba. A végén jelenítse meg a cél View-t és távolítsa el a snapshotot.

swift
import UIKit

"> Egyéni Shared Element animátor
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
        }

        // A közös elem snapshotja
        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 — könyvtár a shared transitions egyszerűsítéséhez
// heroID megegyezik mindkét képernyőn, hasonlóan az Android transitionName-hez
import Hero

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

UIViewPropertyAnimator — az előnyben részesített módszer a megosztott animációkhoz iOS 10+-on. A UIView.animate-tól eltérően a PropertyAnimator támogatja az interaktív vezérlést (fractionComplete), ami lehetővé teszi a shared transition integrálását a swipe-back gesztussal. A Hero könyvtárhoz (harmadik fél) a shared transition a hero.id-n keresztül van beállítva — ez az Android transitionName megfelelője, amely automatikusan animálja a pozíciót, méretet, cornerRadius-t, zPosition-t és backgroundColor-ot a képernyők között.

Shared Element Jetpack Compose-ban

Jetpack Compose-ban a Shared Element Transition a graphicsLayer módosítóval és a SharedTransitionScope (Compose 1.7+) animációval valósítható meg. Minden megosztott elem a sharedElement() segítségével van megjelölve egyedi kulccsal. A rendszer automatikusan animálja a pozíció, méret, forma, szín és vágómaszk változását a composable függvények közötti navigáció során. Az Android Developers Blog (2026) szerint a Compose Shared Element Transition támogatja az AnimatedContent, NavHost és egyedi konténereket.

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 — konténer a megosztott elemekhez
SharedTransitionLayout {
    val sharedTransitionState = remember { SharedTransitionState() }

    // Képernyő A: lista
    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)
            }
        }
    }

    // Képernyő B: részletek (elem kiválasztásakor jelenik meg)
    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 — új API, amely kísérleti módban érhető el. Felváltja a megosztott animációk manuális kezelését a NavHost-ban. Fő képességek: boundsTransform egyedi animációs görbéhez, clipToBounds lekerekített sarkokhoz, zIndex rétegezési sorrendhez. Különböző contentScale-el rendelkező képek animálásához használja a Modifier.sharedElement-t SharedContentKey wrapperrel. Az régebbi Compose verziók (< 1.7) támogatásához használja a Google SharedTransitionScope könyvtárát.

Optimalizálás és tipikus problémák

Shared Element Transition teljesítményproblémákat okozhat, ha nem veszik figyelembe a platform korlátozásait. Androidban a fő probléma a ChangeImageTransform nagy képekkel (2048 px felett). iOS-ben — snapshot nehéz rétegekkel (CAGradientLayer, CAShapeLayer sok csomóponttal). Megoldás: használjon tömörített képeket a megosztott animációhoz, és készítsen snapshotot afterScreenUpdates: false paraméterrel.

ProblémaOkMegoldás
Rángatózó animációEltérő layout az átmenet előtt/után / nehéz snapshotHasználjon Placeholdert: jelenítsen meg kis előnézetet betöltéskor
A megosztott elem nem animálódikA transitionName nem egyezik mindkét képernyőnEllenőrizze a transitionName pontos egyezését XML/kódban
FPS < 40 AndroidonA megosztott elem összetett View hierarchiát tartalmazCsak az ImageView-t ossza meg, ne a teljes CardView-t
iOS: snapshot műtermékekrenderInContext maszkokkal/animációkkal rendelkező rétegenHasználja a drawHierarchy(in:afterScreenUpdates: true) függvényt
Compose: elem nem jelenik megA SharedTransitionLayout nem fedi mindkét képernyőtA SharedTransitionLayout-nak szülőnek kell lennie mindkettőhöz
kotlin
// Optimalizálás: Placeholder a képhez shared transition-ben
import androidx.core.widget.ImageViewCompat
import com.bumptech.glide.Glide

"> Preview betöltése navigáció előtt
Glide.with(context)
    .load(imageUrl)
    .override(300, 300) // Méretkorlátozás shared transition-hez
    .placeholder(R.drawable.placeholder)
    .into(imageView)

> A full-resolution késleltetett betöltése az átmenet után
val detailImage = findViewById<ImageView>(R.id.detailImage)
detailImage.doOnPreDraw {
    Glide.with(context).load(imageUrl).into(detailImage)
}

// iOS: snapshot optimalizálása drawHierarchy-val
// snapshotView(afterScreenUpdates: false) — gyorsabb, figyelmen kívül hagyja a függőben lévő frissítéseket
// Összetett View-okhoz: drawHierarchy(in: view.bounds, afterScreenUpdates: true)

Legjobb gyakorlatok: ne adjon hozzá 3-nál több megosztott elemet átmenetenként — minden további elem növeli a renderelési terhelést. Listák (RecyclerView/UICollectionView) esetén a megosztott elemet a kattintott item-en végezze, ne a teljes listán. Lekerekített sarkú kártyákhoz használja a clipToOutline-t Androidban vagy a cornerRadius-t a snapshotban iOS-ben. Ha a megosztott elem a második képernyőn ScrollView-ban van, várja meg a layout befejeződését (view.doOnPreDraw) az animáció megkezdése előtt.

Gyakran Ismételt Kérdések

Hány megosztott elem animálható egyetlen átmenetben?

Átmenetenként legfeljebb 3 megosztott elem ajánlott. Minden további elem növeli a renderelési terhelést és FPS csökkenést okozhat. Optimális: 1 kép + 1 szöveg (cím). Androidban minden elem az addSharedElement(view, transitionName) segítségével adható hozzá. iOS-ben minden snapshot külön kerül a containerView-be.

Nem működik a Shared Element Transition RecyclerView-val — mit tegyek?

Győződjön meg róla, hogy a transitionName dinamikusan van beállítva az onBindViewHolder-ban: holder.imageView.transitionName = «image_${position}». A FragmentTransaction.addSharedElement számára adja át a konkrét View-t a holder-ból. Az ActivityOptions számára használja a Pair.create(holder.imageView, holder.imageView.transitionName) függvényt. Halassza el a shared transition-t a layout befejeződéséig a postponeEnterTransition() és startPostponedEnterTransition() segítségével.

Hogyan készítsünk Shared Element Transition-t háttérszín változtatással?

Androidban: adja hozzá a ChangeBackground-ot a TransitionSet-hez, vagy használjon egyedi Transition-t, amely felülírja a captureStartValues és captureEndValues értékeket. iOS-ben: animálja a snapshot backgroundColor-ját vagy a UIViewPropertyAnimator-t színváltoztatással. Jetpack Compose-ban: a Modifier.sharedElement automatikusan animálja a background-ot a Color transition segítségével. Kártyák esetén animálja az elevation-t is — 2dp-ről a listán 8dp-re a részletes képernyőn.

Működik a Shared Element Androidban Jetpack Navigation-nel?

Igen, a Navigation Component-tel a Shared Element támogatott a NavOptions segítségével: val navOptions = NavOptions.Builder().setEnterAnim(R.transition.move).applyNavOptions(fragment). Használja a FragmentNavigatorExtras-t a megosztott elemek átadásához: FragmentNavigatorExtras(view to transitionName). A Navigation Compose-hoz használja a Modifier.sharedElement-t a SharedTransitionScope-ból (Compose 1.7+).

Hogyan lehet hibakeresni a Shared Element Transition-t?

Androidban kapcsolja be a Transition Debugging-ot: adb shell setprop debug.transition 1 — a logcat-ben megjelennek a megosztott elemek rögzítéséről és animálásáról szóló üzenetek. Kapcsolja be a «Show layout bounds»-ot a Developer Options-ban a határok előtte/utána ellenőrzéséhez. iOS-ben használja a Debug View Hierarchy-t a snapshot containerView-ben történő ellenőrzéséhez. FPS monitorozáshoz használja a Profile GPU Rendering (Android) vagy Core Animation instrument (iOS) eszközt.

Összefoglalás

  • Shared Element Transition — közös elem animációja képernyők között a vizuális kontextus megtartásával.
  • Android: FragmentTransaction.addSharedElement vagy ActivityOptions.makeSceneTransitionAnimation.
  • iOS: egyedi implementáció a UIViewControllerAnimatedTransitioning + snapshot + PropertyAnimator segítségével.
  • Jetpack Compose: Modifier.sharedElement a SharedTransitionScope-ból (Compose 1.7+).
  • Maximum 3 megosztott elem átmenetenként az FPS csökkenés elkerülése érdekében.
  • Különböző scaleType ImageView-hoz használja a ChangeImageTransform-ot (Android) vagy snapshotot (iOS).
  • Hero könyvtár (iOS) — harmadik féltől származó megoldás hero.id-val, hasonlóan az Android transitionName-hez.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is