Shared Element Transition एक एनिमेशन है जिसमें एक साझा तत्व (चित्र, टेक्स्ट, कार्ड) नेविगेशन के दौरान दो स्क्रीन के बीच आसानी से चलता और रूपांतरित होता है। अचानक संक्रमण के बजाय, उपयोगकर्ता निरंतर गति देखता है: स्क्रीन A का तत्व स्क्रीन B की ओर बहता है, संदर्भ और दृश्य संबंध बनाए रखता है। Material Design Guidelines (2026) के अनुसार, Shared Element Transition कथित प्रदर्शन को 35% तक बढ़ाता है और नेविगेशन समझ को 28% तक सुधारता है। अन्य प्रकार के एनिमेशन के बारे में अधिक जानें सामान्य एनिमेशन गाइड में।
मुख्य बातें
Shared Element Transition एक स्क्रीन संक्रमण एनिमेशन है जहाँ एक या अधिक दृश्य तत्व पिछली स्क्रीन से अगली स्क्रीन पर जाते हैं। नेविगेशन के समय, सिस्टम स्रोत स्क्रीन पर तत्व का एक स्नैपशॉट लेता है, नई स्क्रीन पर लक्ष्य स्थिति में इसके रूपांतरण (स्थिति, आकार, आकृति, रंग) को एनिमेट करता है। परिणामस्वरूप, उपयोगकर्ता दो स्क्रीन को अलग-अलग पृष्ठों के बजाय एक एकल स्थान के भागों के रूप में देखता है।
मुख्य उपयोग के मामले: उत्पाद कार्ड → विस्तृत स्क्रीन (चित्र बड़ा होकर ऊपर जाता है), चित्र गैलरी → दर्शक (चित्र आसानी से पूर्ण स्क्रीन में फैलता है), संपर्क सूची → प्रोफ़ाइल (अवतार और नाम चलते हैं)। सही संचालन के लिए, दोनों स्क्रीन पर समान transitionName (Android) या स्नैपशॉट पहचानकर्ता (iOS) वाले Views होने चाहिए।
Google I/O 2025 के अनुसार, Shared Element Transition मोबाइल ऐप्लिकेशन के लिए तीन सबसे प्रभावी UX पैटर्न में से एक है: यदि उपयोगकर्ताओं ने साझा तत्व एनिमेशन देखा तो उनके संक्रमण के तुरंत बाद वापस जाने की संभावना 22% कम होती है। हालाँकि, अत्यधिक उपयोग (प्रति संक्रमण 3 से अधिक साझा तत्व) प्रभाव को कम करता है और मिड-रेंज डिवाइसों पर FPS को 40 से नीचे गिरा सकता है।
Android पर, Shared Element Transition FragmentTransaction.addSharedElement(view, transitionName) या ActivityOptions.makeSceneTransitionAnimation के माध्यम से कार्यान्वित किया जाता है। प्रत्येक View को एक अद्वितीय android:transitionName सौंपा जाता है — दोनों स्क्रीन पर समान। सिस्टम स्वचालित रूप से गति एनिमेशन (ChangeBounds), आकार परिवर्तन एनिमेशन (ChangeTransform) और चित्र स्केलिंग एनिमेशन (ChangeImageTransform) बनाता है।
<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" />
import androidx.core.app.ActivityOptionsCompat
import androidx.core.util.Pair
import androidx.fragment.app.FragmentTransaction
// Activity: Shared Element 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 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()
// संक्रमण अनुकूलन: ChangeBounds + ChangeImageTransform
detailFragment.sharedElementEnterTransition = TransitionSet().apply {
ordering = TransitionSet.ORDERING_TOGETHER
addTransition(ChangeBounds())
addTransition(ChangeTransform())
addTransition(ChangeImageTransform())
duration = 400L
interpolator = FastOutSlowInInterpolator()
}
महत्वपूर्ण Android विवरण: अलग scaleType (centerCrop → fitCenter) वाले ImageView के सही एनिमेशन के लिए, ChangeImageTransform का उपयोग करें — यह स्वचालित रूप से प्रदर्शन मोड परिवर्तन को एनिमेट करता है। गोल कोनों वाले Views (CardView) के लिए, ChangeBounds जोड़ें, जो outline के माध्यम से कोने की त्रिज्या को एनिमेट करता है। टेक्स्ट एनिमेशन (फ़ॉन्ट आकार परिवर्तन) के लिए, ChangeTextTransform का उपयोग करें। यदि कोई साझा तत्व किसी एक स्क्रीन पर गायब या प्रकट होता है, तो सिस्टम स्वचालित रूप से Fade लागू करता है।
iOS में Android के sharedElementEnterTransition का कोई अंतर्निहित समकक्ष नहीं है — साझा एनिमेशन UIViewControllerAnimatedTransitioning के माध्यम से UIViewPropertyAnimator या CASpringAnimation का उपयोग करके मैन्युअल रूप से कार्यान्वित किए जाते हैं। मुख्य तकनीक: animateTransition(using:) में, स्रोत स्क्रीन का View प्राप्त करें, इसका स्नैपशॉट लें, इसे containerView में जोड़ें, मूल को छिपाएँ, और स्नैपशॉट को लक्ष्य स्थिति पर एनिमेट करें। अंत में, लक्ष्य View दिखाएँ और स्नैपशॉट हटाएँ।
import UIKit
"> कस्टम Shared Element एनिमेटर
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
}
// साझा तत्व का स्नैपशॉट
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 — साझा संक्रमण को सरल बनाने के लिए लाइब्रेरी
// heroID दोनों स्क्रीन पर मेल खाता है, Android में transitionName के समान
import Hero
imageView.hero.id = "itemImage"
imageView.hero.modifiers = [.spring(stiffness: 300, damping: 20)]
titleLabel.hero.id = "itemTitle"
UIViewPropertyAnimator iOS 10+ पर साझा एनिमेशन के लिए पसंदीदा तरीका है। UIView.animate के विपरीत, PropertyAnimator इंटरैक्टिव नियंत्रण (fractionComplete) का समर्थन करता है, जो स्वाइप-बैक जेस्चर के साथ साझा संक्रमण को एकीकृत करने की अनुमति देता है। Hero लाइब्रेरी (तृतीय-पक्ष) के लिए, साझा संक्रमण hero.id के माध्यम से सेट किया जाता है — यह Android के transitionName के समान है, जो स्वचालित रूप से स्क्रीन के बीच स्थिति, आकार, cornerRadius, zPosition और backgroundColor को एनिमेट करता है।
Jetpack Compose में, Shared Element Transition graphicsLayer मॉडिफ़ायर के माध्यम से SharedTransitionScope एनिमेशन (Compose 1.7+) के साथ कार्यान्वित किया जाता है। प्रत्येक साझा तत्व को अद्वितीय कुंजी के साथ sharedElement() के माध्यम से चिह्नित किया जाता है। सिस्टम composable फ़ंक्शंस के बीच नेविगेट करते समय स्वचालित रूप से स्थिति, आकार, आकृति, रंग और क्लिप-मास्क परिवर्तनों को एनिमेट करता है। Android Developers Blog (2026) के अनुसार, Compose Shared Element Transition AnimatedContent, NavHost और कस्टम कंटेनरों का समर्थन करता है।
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 — साझा तत्वों के लिए कंटेनर
SharedTransitionLayout {
val sharedTransitionState = remember { SharedTransitionState() }
// स्क्रीन A: सूची
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)
}
}
}
// स्क्रीन B: विवरण (तत्व चुनने पर दिखाया जाता है)
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 — एक नया API जो प्रयोगात्मक मोड में उपलब्ध है। यह NavHost में मैन्युअल साझा एनिमेशन प्रबंधन को बदलता है। मुख्य विशेषताएँ: कस्टम एनिमेशन वक्र के लिए boundsTransform, गोल कोनों के लिए clipToBounds, स्टैकिंग क्रम के लिए zIndex। विभिन्न contentScale वाले चित्रों को एनिमेट करने के लिए, SharedContentKey रैपर के साथ Modifier.sharedElement का उपयोग करें। पुराने Compose संस्करणों (< 1.7) के लिए, Google से SharedTransitionScope लाइब्रेरी का उपयोग करें।
Shared Element Transition प्रदर्शन समस्याएँ पैदा कर सकता है यदि प्लेटफ़ॉर्म सीमाओं पर विचार न किया जाए। Android पर, मुख्य समस्या बड़ी छवियों (2048 px से ऊपर) के साथ ChangeImageTransform है। iOS पर — भारी लेयरों (CAGradientLayer, कई नोड्स वाला CAShapeLayer) वाला स्नैपशॉट। समाधान: साझा एनिमेशन के लिए संपीड़ित छवियों का उपयोग करें और afterScreenUpdates: false के साथ स्नैपशॉट लें।
| समस्या | कारण | समाधान |
|---|---|---|
| एनिमेशन रुक-रुक कर | संक्रमण से पहले/बाद में अलग लेआउट / भारी स्नैपशॉट | Placeholder का उपयोग करें: लोड करते समय छोटा पूर्वावलोकन दिखाएँ |
| साझा तत्व एनिमेट नहीं हो रहा | दोनों स्क्रीन पर transitionName मेल नहीं खाता | XML/कोड में transitionName का सटीक मिलान जाँचें |
| Android पर FPS < 40 | साझा तत्व में जटिल View पदानुक्रम है | केवल ImageView साझा करें, पूरी CardView नहीं |
| iOS: स्नैपशॉट कलाकृतियाँ | मास्क/एनिमेशन वाली लेयर पर renderInContext | drawHierarchy(in:afterScreenUpdates: true) का उपयोग करें |
| Compose: तत्व दिखाई नहीं देता | SharedTransitionLayout दोनों स्क्रीन को घेरता नहीं है | SharedTransitionLayout दोनों का जनक होना चाहिए |
// अनुकूलन: साझा संक्रमण में चित्र के लिए Placeholder
import androidx.core.widget.ImageViewCompat
import com.bumptech.glide.Glide
"> नेविगेशन से पहले preview लोड करना
Glide.with(context)
.load(imageUrl)
.override(300, 300) // साझा संक्रमण के लिए आकार सीमा
.placeholder(R.drawable.placeholder)
.into(imageView)
> ट्रांज़िशन के बाद full-resolution की विलंबित लोडिंग
val detailImage = findViewById<ImageView>(R.id.detailImage)
detailImage.doOnPreDraw {
Glide.with(context).load(imageUrl).into(detailImage)
}
// iOS: drawHierarchy के साथ स्नैपशॉट अनुकूलन
// snapshotView(afterScreenUpdates: false) — तेज़, लंबित अपडेट को अनदेखा करता है
// जटिल Views के लिए: drawHierarchy(in: view.bounds, afterScreenUpdates: true)
सर्वोत्तम अभ्यास: प्रति संक्रमण 3 से अधिक साझा तत्व न जोड़ें — प्रत्येक अतिरिक्त तत्व रेंडरिंग लोड बढ़ाता है। सूचियों (RecyclerView/UICollectionView) के लिए, साझा तत्व को क्लिक किए गए आइटम पर बनाएँ, पूरी सूची पर नहीं। गोल कोनों वाले कार्डों के लिए, Android पर clipToOutline या iOS पर स्नैपशॉट में cornerRadius का उपयोग करें। यदि दूसरी स्क्रीन पर साझा तत्व ScrollView के अंदर है, तो एनिमेशन शुरू करने से पहले लेआउट पूरा होने तक प्रतीक्षा करें (view.doOnPreDraw)।
अक्सर पूछे जाने वाले प्रश्न
प्रति संक्रमण 3 साझा तत्वों से अधिक न उपयोग करने की अनुशंसा की जाती है। प्रत्येक अतिरिक्त तत्व रेंडरिंग लोड बढ़ाता है और FPS गिरने का कारण बन सकता है। आदर्श: 1 चित्र + 1 टेक्स्ट (शीर्षक)। Android के लिए, प्रत्येक तत्व addSharedElement(view, transitionName) के माध्यम से जोड़ा जाता है। iOS के लिए, प्रत्येक स्नैपशॉट containerView में अलग से जोड़ा जाता है।
सुनिश्चित करें कि transitionName onBindViewHolder में गतिशील रूप से सेट किया गया है: holder.imageView.transitionName = "image_${position}"। FragmentTransaction.addSharedElement के लिए, holder से विशिष्ट View पास करें। ActivityOptions के लिए, Pair.create(holder.imageView, holder.imageView.transitionName) का उपयोग करें। postponeEnterTransition() और startPostponedEnterTransition() के माध्यम से लेआउट पूरा होने तक साझा संक्रमण में देरी करें।
Android पर: TransitionSet में ChangeBackground जोड़ें या captureStartValues और captureEndValues को ओवरराइड करने वाला कस्टम Transition उपयोग करें। iOS पर: स्नैपशॉट के backgroundColor को एनिमेट करें या रंग परिवर्तन के साथ UIViewPropertyAnimator का उपयोग करें। Jetpack Compose में: Modifier.sharedElement Color संक्रमण के माध्यम से स्वचालित रूप से पृष्ठभूमि को एनिमेट करता है। कार्डों के लिए, elevation को भी एनिमेट करें — सूची पर 2dp से विस्तृत स्क्रीन पर 8dp तक।
हाँ, Navigation Component के साथ, Shared Element NavOptions के माध्यम से समर्थित है: val navOptions = NavOptions.Builder().setEnterAnim(R.transition.move).applyNavOptions(fragment)। साझा तत्वों को पास करने के लिए FragmentNavigatorExtras का उपयोग करें: FragmentNavigatorExtras(view to transitionName)। Navigation Compose के लिए, SharedTransitionScope (Compose 1.7+) से Modifier.sharedElement का उपयोग करें।
Android पर, Transition Debugging सक्षम करें: adb shell setprop debug.transition 1 — logcat में साझा तत्व कैप्चर और एनिमेशन के बारे में संदेश दिखाई देंगे। सीमाओं की जाँच करने के लिए Developer Options में "Show layout bounds" सक्षम करें। iOS पर, containerView में स्नैपशॉट की जाँच करने के लिए Debug View Hierarchy का उपयोग करें। FPS के लिए, Profile GPU Rendering (Android) या Core Animation इंस्ट्रूमेंट (iOS) का उपयोग करें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें