Hero Animation: Flutter’da ortak öğe geçişi nedir

Yazar: IT Sectr Yayınlanma: 2026-03-02 Okuma süresi: 8 dk
Hero Animation, bir arayüz öğesinin ekranlar arasında sorunsuz bir şekilde hareket ettiği ve dönüştüğü, bir bağlamdan diğerine seyahat eden bir “kahraman” etkisi yaratan bir animasyon desenidir. Standart bir push/pop geçişinin aksine, kahraman animasyonu görsel sürekliliği korur: kullanıcı küçük resmin tam ekran görüntüye dönüştüğünü veya bir hücre başlığının ekran başlığına taşındığını görür. Google Material Design’a (2025) göre, Hero Animation, liste ve detay arasında gezinirken bilişsel yükü %30 azaltır — kullanıcı, öğenin konumunu hatırladığı için odak kaybetmez. Flutter’da desen Hero widget‑ı aracılığıyla, SwiftUI’de matchedGeometryEffect değiştiricisi aracılığıyla, Jetpack Compose’da Modifier.sharedElement aracılığıyla uygulanır.

Önemli noktalar

  • Hero Animation — kullanıcı için görsel bağlamı koruyan, ekranlar arasında sorunsuz bir ortak öğe geçişi.
  • Flutter Hero — etiketle otomatik olarak bir çift bulan ve ekranlar arasında FlightShuttle animasyonu başlatan bir widget.
  • matchedGeometryEffect — animasyonlu geçişler için bir ad alanındaki tanımlayıcı aracılığıyla öğeleri birbirine bağlayan bir SwiftUI değiştiricisi.
  • Shared Element Transition — ActivityOptions veya Jetpack Compose’da Modifier.sharedElement aracılığıyla uygulanan bir Android mekanizması.
  • FlightShuttle — geçiş sırasında Hero widget‑ının yörüngesini ve dönüşümünü kontrol eden Flutter’ın iç mekanizması.

Hero Animation Nedir?

Hero Animation, ortak bir öğenin kaynak ekrandan hedef ekrana sorunsuz bir şekilde hareket ederek kimliğini koruduğu bir UI animasyon tekniğidir. İsim, ekranlar arasında senaryolu bir geçişten geçen ve kullanıcının dikkatini çeken anahtar bir öğe olan bir “kahraman” metaforunu yansıtır. Standart geçişlerin aksine, Hero Animation görsel bağlantıyı kesmez: kullanıcı öğenin sürekli bir yörüngesini görür ve gezinme hiyerarşisini daha iyi anlar.

Hero Animation kavramı, Material Design’da liste-detay ekranları, galeriler ve kartlar için bir öneri olarak yerleşmiştir. Animasyon algoritması üç aşamadan oluşur: kaynak ekranda öğe vurgulanır ve mutlak bir konuma sabitlenir; geçiş sırasında hedef kapsayıcıya göre ölçeklenir, hareket eder ve şekil değiştirir; son ekranda öğe yeni düzene gömülür. Material Design 3’e göre, doğru şekilde uygulanan bir kahraman animasyonu, hatalı “geri” düğmesine basma sayısını %22 azaltır.

Flutter’da Hero: Etiketler ve FlightShuttle

Flutter’da Hero Animation, zorunlu bir parametre olan tag’i — benzersiz bir tanımlayıcı — alan Hero widget‑ı aracılığıyla uygulanır. Flutter, kaynak ve hedef yollarında aynı etikete sahip Hero widget çiftini otomatik olarak bulur ve animasyonu başlatır. Hero widget‑ı manuel animasyon yönetimi gerektirmez — framework, yörüngeleri bağımsız olarak hesaplar ve dönüşümü iç FlightShuttle nesnesi aracılığıyla uygular.

FlightShuttle, geçiş anında Hero widget‑ının bir kaplama kopyasını oluşturan, onu mutlak bir koordinat sistemine yerleştiren ve dönüşümü (boyutlandırma, öteleme, döndürme) başlangıç konumundan son konuma canlandıran görünmez bir “mekik”tir. flightShuttleBuilder özelliği aracılığıyla FlightShuttle’a özel eğriler iletilebilir, bu da uçuş yörüngesini kontrol etmeye olanak tanır. Flutter 3.16+’da Hero, clipRect ve borderRadius’u koruyarak animasyonu destekler ve yuvarlak kartların dikdörtgen ekranlara dönüşmesi efekti verir.

SwiftUI’de matchedGeometryEffect

SwiftUI’de Hero Animation’ın eşdeğeri, iOS 14’te tanıtılan matchedGeometryEffect değiştiricisidir. İki öğeyi bir tanımlayıcı (id) ve bir ad alanı (namespace) aracılığıyla birbirine bağlar. Hero’nun geçişi otomatik olarak ele geçirdiği Flutter’ın aksine, SwiftUI, ad alanının açıkça bildirilmesini ve değiştiricinin aynı hiyerarşi içinde veya GeometryReader aracılığıyla sahnenin her iki bölümüne (kaynak ve hedef) uygulanmasını gerektirir.

matchedGeometryEffect animasyonu, konum, boyut, dönüş ve köşe yarıçapının dönüşümünü destekler. Akıcılık için withAnimation içinde bir Animation belirtilir. SwiftUI, varsayılan easeInOut eğrisine dayalı olarak ara durumları otomatik olarak enterpolasyon yapar. iOS 17+’da, TabView ve NavigationStack için matchedTransitionSource desteği eklendi — standart geçişler için önceden tanımlanmış bir yörüngeye sahip Hero Animation’ın bir sistem analogu.

Android’de Shared Element Transition

Android’de Hero Animation, Shared Element Transition olarak adlandırılır ve ActivityOptions.makeSceneTransitionAnimation veya FragmentTransaction.addSharedElement aracılığıyla uygulanır. Her ortak öğe, XML’de bir transitionName özelliği veya kod aracılığıyla işaretlenir ve Android, etkinlikler arasındaki animasyonu yönetir. Android 5.0’dan (API 21) itibaren geçişler framework’ün bir parçası haline geldi; bundan önce, ValueAnimator kullanılarak özel animasyonlar yazılması gerekiyordu.

Jetpack Compose’da Shared Element Transition, Modifier.sharedElement ve Modifier.sharedBounds değiştiricileri aracılığıyla AnimatedContent veya SharedTransitionLayout (Compose BOM 2024.01’den itibaren mevcut) ile birlikte uygulanır. View sisteminin aksine, Compose öğeleri tembel bir şekilde yeniden çizer, bu nedenle ortak öğe CompositionLocal’da önbelleğe alınır. Compose ayrıca scrollOffset’u koruyarak listeden detaya animasyonu destekler — Hero geçişleri için önemli bir yetenek. Google I/O 2024’e göre, Compose Shared Element Transition, doğrudan RenderNode yönetimi sayesinde View sürümünden %15 daha hızlıdır.

Kod örnekleri

Flutter: Görsel ile Hero

Flutter’da Hero Animation’ın temel bir örneği: liste ekranında bir küçük resim ve detay ekranında tam ekran bir görüntü. image-hero etiketi iki widget‑ı birbirine bağlar ve FlightShuttle, karttan tam ekrana geçişi otomatik olarak canlandırır.

dart
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,
          ),
        ),
      ),
    );
  }
}

Anahtar nokta, her iki ekranda da aynı etiket (image-hero) kullanılmasıdır. Flutter, rota geçişi sırasında Hero widget‑larını etikete göre eşleştirir. Etiketler farklıysa, animasyon başlamaz — öğe yeni ekranda geçiş olmadan görünür. Etiket için herhangi bir tür kullanılabilir, ancak dizeler en güvenilir seçenektir.

SwiftUI: Ekranlar arasında matchedGeometryEffect

NavigationStack ile SwiftUI’de Hero Animation örneği. matchedGeometryEffect değiştiricisi, listedeki görseli ve detay ekranını bir ad alanı aracılığıyla birbirine bağlar ve withAnimation sorunsuz bir geçişi tetikler.

swift
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, matchedGeometryEffect tanımlayıcısı için bir ad alanı oluşturur. Her iki öğe de aynı id’yi (“hero”) ve paylaşılan bir ad alanını kullanır. isDetailShown değiştiğinde, SwiftUI iki görünüm arasındaki boyut, konum ve köşe yarıçapı dönüşümünü canlandırarak kahraman efekti yaratır. iOS 16+ ile standart bir NavigationLink için navigationTransition(.hero) kullanın.

Android: Jetpack Compose ile Shared Element Transition

SharedTransitionLayout ile Jetpack Compose’da Shared Element Transition örneği. sharedElement değiştiricisi, gezinme sırasında ekranlar arasında ortak bir öğeyi canlandırır.

kotlin
@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+) hiyerarşiyi sarar ve “hero” anahtarına sahip sharedElement değiştiricisi, başlangıç ve bitiş öğelerini birbirine bağlar. AnimatedContent durumu değiştirir ve Compose, görselin boyutunu, konumunu ve şeklini otomatik olarak canlandırır. Temel bir avantaj, geçiş sırasında kart yuvarlama efekti sağlayan bounds ve clipBounds animasyonu desteğidir.

Sıkça sorulan sorular

Hero Animation iOS ve Android’de çalışır mı?

Evet, Hero Animation her iki platformda da kullanılabilir. iOS, SwiftUI’de matchedGeometryEffect veya UINavigationController.transitioningDelegate kullanır. Android, ActivityOptions.makeSceneTransitionAnimation veya Jetpack Compose’da Modifier.sharedElement ile Shared Element Transition kullanır. Flutter, Hero Animation’ı Hero widget‑ı aracılığıyla uygular ve her iki platformda aynı şekilde çalışır.

Birden çok öğe aynı anda canlandırılabilir mi?

Evet, Hero Animation birden çok ortak öğeyi destekler. Flutter’da farklı etiketlere sahip birden çok Hero widget‑ı belirtin. SwiftUI’de her öğede farklı tanımlayıcılarla matchedGeometryEffect kullanın. Tüm animasyonlar paralel olarak çalışır — her öğe kendi yörüngesinde hareket eder.

Hero Animation büyük görsellerde yavaşlar mı?

Performans uygulamaya bağlıdır. Flutter FlightShuttle, görselleri RenderObject aracılığıyla işleyerek 60fps’ye ulaşır. SwiftUI matchedGeometryEffect vektörleştirilmiştir. Büyük görseller için Flutter’da precacheImage veya SwiftUI’de prefetch kullanın — bu, ilk geçişteki gecikmeleri ortadan kaldırır. Android Compose, AsyncImage aracılığıyla gecikmeli yükleme gerektirir.

Hero, standart push geçişinden nasıl farklıdır?

Standart bir push geçişi tüm ekranı kaydırarak bir kart yığını yanılsaması yaratır. Hero Animation görsel dikkati tek bir öğeye sabitler — kullanıcı onun sürekli hareketini görür ve ekranlar arasındaki ilişkiyi daha iyi anlar. Push hiyerarşik gezinme için, Hero içeriği vurgulamak için uygundur.

Hero Animation için ek kitaplıklar gerekli mi?

Hayır, Hero Animation yerleşik araçlarla uygulanır. Flutter’da flutter/material.dart paketinden Hero widget‑ıdır. SwiftUI’de matchedGeometryEffect değiştiricisidir. Android Jetpack Compose’da standart Compose’dan SharedTransitionLayout ve Modifier.sharedElement’dir. Ek kitaplıklar yalnızca standart olmayan yörüngeler veya karmaşık dönüşümler için gereklidir.

Özet

  • Hero Animation, görsel sürekliliği koruyan ve bilişsel yükü azaltan, ekranlar arasında bir ortak öğe geçişidir.
  • Flutter Hero etiket ve FlightShuttle ile manuel animasyon yönetimi olmadan kahraman animasyonu uygulamanın en basit yoludur.
  • SwiftUI matchedGeometryEffect @Namespace.id ile bir öğenin konumunu, boyutunu ve köşe yarıçapını iki durum arasında canlandırır.
  • Android SharedTransitionLayout, Jetpack Compose’da Modifier.sharedElement ile RenderNode önbelleklemesiyle geçişler sağlar.
  • Her üç framework de paralel animasyonla birden çok ortak öğeyi destekler.
  • FlightShuttle, Flutter’da flightShuttleBuilder aracılığıyla uçuş yörüngesini özelleştirmeye olanak tanır.
  • Hero Animation, Material Design tarafından liste-detay ekranları, galeriler ve kartlar için önerilir.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun