Fragment API, gezinme sırasında parçaları görsel olarak bağlamak için hareket efektlerini ve dönüşümleri kullanmanın iki yolunu sunar. Bunlardan biri, hem Animation
hem de Animator
kullanan Animasyon Çerçevesi'dir. Diğeri ise paylaşılan öğe geçişlerini içeren Geçiş Çerçevesi'dir.
Parçalara girmek, parçalardan çıkmak ve paylaşılan öğelerin parçalar arasındaki geçişleri için özel efektler belirtebilirsiniz.
- Enter efekti, bir parçanın ekrana nasıl gireceğini belirler. Örneğin, parçaya gittiğinizde ekranın kenarından içine kaydıracak bir efekt oluşturabilirsiniz.
- Çıkış efekti, bir parçanın ekrandan nasıl çıkacağını belirler. Örneğin, parçadan çıkarken parçayı şeffaflaştırmak için bir efekt oluşturabilirsiniz.
- Paylaşılan öğe geçişi, iki parça arasında paylaşılan bir görünümün bunlar arasında nasıl hareket edeceğini belirler. Örneğin, A parçasındaki
ImageView
içinde gösterilen bir resim, B görünür hale geldiğinde B parçasına geçer.
Animasyonları değiştirme
Öncelikle, yeni bir parçaya giderken çalıştırılan giriş ve çıkış efektleriniz için animasyonlar oluşturmanız gerekir. Animasyonları, animasyon kaynakları ara sayısı olarak tanımlayabilirsiniz. Bu kaynaklar, animasyon sırasında parçaların nasıl döndürüleceğini, uzatılacağını, kaybolacağını ve hareket edeceğini tanımlamanızı sağlar. Örneğin, Şekil 1'de gösterildiği gibi mevcut parçanın şeffaflaşmasını ve yeni parçanın ekranın sağ kenarından kaymasını isteyebilirsiniz.
![Animasyonlara giriş ve çıkış. Sonraki parça sağdan kayarak kaybolurken mevcut parça kaybolur.](https://developer.android.com/static/images/training/basics/fragments/enter-exit-animation.gif?authuser=5&hl=tr)
Bu animasyonlar res/anim
dizininde tanımlanabilir:
<!-- res/anim/fade_out.xml -->
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="1"
android:toAlpha="0" />
<!-- res/anim/slide_in.xml -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="100%"
android:toXDelta="0%" />
Ayrıca, kullanıcı Yukarı veya Geri düğmesine dokunduğunda gerçekleşebilecek, arka yığın açılırken çalıştırılacak giriş ve çıkış efektleri için animasyonlar da belirleyebilirsiniz. Bunlara, popEnter
ve popExit
animasyonları denir. Örneğin, bir kullanıcı önceki bir ekrana geri döndüğünde mevcut parçanın ekranın sağ kenarından kaymasını ve önceki parçanın belirmesini isteyebilirsiniz.
![popEnter ve popExit animasyonları. Mevcut parça, ekrandan sağa doğru kayarken önceki parça belirir.](https://developer.android.com/static/images/training/basics/fragments/pop-animations.gif?authuser=5&hl=tr)
popEnter
ve
popExit
animasyonları. Mevcut parça, ekrandan sağa doğru kayarken önceki parça belirir.Bu animasyonlar şu şekilde tanımlanabilir:
<!-- res/anim/slide_out.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="0%"
android:toXDelta="100%" />
<!-- res/anim/fade_in.xml -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0"
android:toAlpha="1" />
Animasyonlarınızı tanımladıktan sonra, aşağıdaki örnekte gösterildiği gibi, FragmentTransaction.setCustomAnimations()
yöntemini çağırarak animasyon kaynaklarınızı kaynak kimlikleriyle ileterek kullanın:
Kotlin
supportFragmentManager.commit { setCustomAnimations( R.anim.slide_in, // enter R.anim.fade_out, // exit R.anim.fade_in, // popEnter R.anim.slide_out // popExit ) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setCustomAnimations( R.anim.slide_in, // enter R.anim.fade_out, // exit R.anim.fade_in, // popEnter R.anim.slide_out // popExit ) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
Geçişleri ayarla
Ayrıca, giriş ve çıkış efektlerini tanımlamak için geçişleri kullanabilirsiniz. Bu geçişler XML kaynak dosyalarında tanımlanabilir. Örneğin, mevcut parçanın solmasını ve yeni parçanın ekranın sağ kenarından kaymasını isteyebilirsiniz. Bu geçişler şu şekilde tanımlanabilir:
<!-- res/transition/fade.xml -->
<fade xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"/>
<!-- res/transition/slide_right.xml -->
<slide xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:slideEdge="right" />
Geçişlerinizi tanımladıktan sonra, aşağıdaki örnekte gösterildiği gibi, giriş parçasında setEnterTransition()
ve çıkış parçada setExitTransition()
yöntemini çağırıp şişirilmiş geçiş kaynaklarınızı kaynak kimlikleriyle geçirerek bunları uygulayın:
Kotlin
class FragmentA : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val inflater = TransitionInflater.from(requireContext()) exitTransition = inflater.inflateTransition(R.transition.fade) } } class FragmentB : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(R.transition.slide_right) } }
Java
public class FragmentA extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TransitionInflater inflater = TransitionInflater.from(requireContext()); setExitTransition(inflater.inflateTransition(R.transition.fade)); } } public class FragmentB extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TransitionInflater inflater = TransitionInflater.from(requireContext()); setEnterTransition(inflater.inflateTransition(R.transition.slide_right)); } }
Parçalar AndroidX geçişlerini destekler. Parçalar çerçeve geçişlerini de desteklese de, API seviyeleri 14 ve sonraki sürümlerde desteklendiğinden ve çerçeve geçişlerinin eski sürümlerinde bulunmayan hata düzeltmeleri içerdiğinden AndroidX geçişlerinin kullanılmasını önemle tavsiye ederiz.
Paylaşılan öğe geçişlerini kullanma
Geçiş Çerçevesi'nin bir parçası olan paylaşılan öğe geçişleri, parça geçişi sırasında karşılık gelen görünümlerin iki parça arasında nasıl hareket edeceğini belirler. Örneğin, Şekil 3'te gösterildiği gibi, A parçasındaki bir ImageView
içinde görüntülenen bir görüntünün, B görünür hale geldiğinde B parçasına geçiş yapmasını isteyebilirsiniz.
![Paylaşılan öğeye sahip parça geçişi.](https://developer.android.com/static/images/training/basics/fragments/shared-element-transition.gif?authuser=5&hl=tr)
Genel hatlarıyla, paylaşılan öğelerle parça geçişinin nasıl yapılacağı aşağıda açıklanmıştır:
- Paylaşılan öğe görünümlerinin her birine benzersiz bir geçiş adı atayın.
FragmentTransaction
'a paylaşılan öğe görünümlerini ve geçiş adlarını ekleyin.- Paylaşılan öğe geçiş animasyonu ayarlayın.
Öncelikle, görünümlerin bir parçadan diğerine eşlenebilmesi için her bir paylaşılan öğe görünümüne benzersiz bir geçiş adı atamanız gerekir. 14 ve sonraki API düzeyleriyle uyumluluk sağlayan ViewCompat.setTransitionName()
kullanarak her parça düzeninde paylaşılan öğeler için bir geçiş adı belirleyin.
Örnek olarak, A ve B parçalarındaki bir ImageView
için geçiş adı aşağıdaki gibi atanabilir:
Kotlin
class FragmentA : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... val itemImageView = view.findViewById<ImageView>(R.id.item_image) ViewCompat.setTransitionName(itemImageView, “item_image”) } } class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... val heroImageView = view.findViewById<ImageView>(R.id.hero_image) ViewCompat.setTransitionName(heroImageView, “hero_image”) } }
Java
public class FragmentA extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... ImageView itemImageView = view.findViewById(R.id.item_image); ViewCompat.setTransitionName(itemImageView, “item_image”); } } public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... ImageView heroImageView = view.findViewById(R.id.hero_image); ViewCompat.setTransitionName(heroImageView, “hero_image”); } }
Paylaşılan öğelerinizi parça geçişine dahil etmek için FragmentTransaction
, her bir paylaşılan öğenin görünümünün bir parçadan diğerine nasıl eşlendiğini bilmelidir. Paylaşılan öğelerinizin her birini, aşağıdaki örnekte gösterildiği gibi FragmentTransaction.addSharedElement()
yöntemini çağırarak ve sonraki parçada bulunan ilgili görünümün geçiş adını geçirerek görünümden geçirerek FragmentTransaction
öğenize ekleyin:
Kotlin
val fragment = FragmentB() supportFragmentManager.commit { setCustomAnimations(...) addSharedElement(itemImageView, “hero_image”) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setCustomAnimations(...) .addSharedElement(itemImageView, “hero_image”) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
Paylaşılan öğelerinizin bir parçadan diğerine nasıl geçiş yapacağını belirtmek için gidilen parçada enter geçişi ayarlamanız gerekir. Aşağıdaki örnekte gösterildiği gibi parçanın onCreate()
yönteminde Fragment.setSharedElementEnterTransition()
yöntemini çağırın:
Kotlin
class FragmentB : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedElementEnterTransition = TransitionInflater.from(requireContext()) .inflateTransition(R.transition.shared_image) } }
Java
public class FragmentB extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Transition transition = TransitionInflater.from(requireContext()) .inflateTransition(R.transition.shared_image); setSharedElementEnterTransition(transition); } }
shared_image
geçişi aşağıdaki şekilde tanımlanır:
<!-- res/transition/shared_image.xml -->
<transitionSet>
<changeImageTransform />
</transitionSet>
Tüm Transition
alt sınıfları, paylaşılan öğe geçişleri olarak desteklenir. Özel bir Transition
oluşturmak istiyorsanız Özel geçiş animasyonu oluşturma konusuna bakın.
Önceki örnekte kullanılan changeImageTransform
, kullanabileceğiniz önceden oluşturulmuş çevirilerden biridir. Transition
sınıfıyla ilgili API referansında ek Transition
alt sınıfları bulabilirsiniz.
Varsayılan olarak, paylaşılan öğe giriş geçişi, paylaşılan öğeler için return geçişi olarak da kullanılır. Dönüş geçişi, parça işlemi arka yığından çıkarıldığında paylaşılan öğelerin önceki parçaya nasıl geri döndüğünü belirler. Farklı bir dönüş geçişi belirtmek isterseniz bunu parçanın onCreate()
yönteminde Fragment.setSharedElementReturnTransition()
kullanarak yapabilirsiniz.
Tahmine dayalı geri uyumluluğu
Hepsi olmasa da çoğu çapraz parça animasyonda tahmine dayalı geri özelliğini kullanabilirsiniz. Tahmine dayalı geri özelliğini uygularken aşağıdaki noktaları göz önünde bulundurun:
Transitions 1.5.0
veya sonraki sürümleri veFragments 1.7.0
ya da sonraki sürümleri içe aktarın.Animator
sınıfı ile alt sınıfları ve AndroidX Transition kitaplığı desteklenir.Animation
sınıfı ve çerçeveTransition
kitaplığı desteklenmiyor.- Tahmine dayalı parça animasyonları yalnızca Android 14 veya sonraki sürümleri çalıştıran cihazlarda çalışır.
setCustomAnimations
,setEnterTransition
,setExitTransition
,setReenterTransition
,setReturnTransition
,setSharedElementEnterTransition
vesetSharedElementReturnTransition
, tahmine dayalı geri ile desteklenir.
Daha fazla bilgi edinmek için Tahmine dayalı geri animasyonları için destek ekleme bölümüne bakın.
Geçişleri erteleme
Bazı durumlarda, parça geçişinizi kısa bir süreliğine ertelemeniz gerekebilir. Örneğin, Android'in geçiş için başlangıç ve bitiş durumlarını doğru bir şekilde yakalayabilmesi amacıyla, giriş parçasındaki tüm görüntülemelerin ölçülüp yerleştirilmesini beklemeniz gerekebilir.
Ayrıca, gerekli bazı veriler yüklenene kadar geçişinizin ertelenmesi gerekebilir. Örneğin, paylaşılan öğeler için resimler yüklenene kadar beklemeniz gerekebilir. Aksi takdirde, geçiş sırasında veya sonrasında bir resmin yüklenmesi biterse geçişte sorun yaşanabilir.
Bir geçişi ertelemek için öncelikle parça işleminin, parça durumu değişikliklerinin yeniden sıralanmasına izin verdiğinden emin olmanız gerekir. Parça durumu değişikliklerinin yeniden düzenlenmesine izin vermek için aşağıdaki örnekte gösterildiği gibi FragmentTransaction.setReorderingAllowed()
çağrısı yapın:
Kotlin
val fragment = FragmentB() supportFragmentManager.commit { setReorderingAllowed(true) setCustomAnimation(...) addSharedElement(view, view.transitionName) replace(R.id.fragment_container, fragment) addToBackStack(null) }
Java
Fragment fragment = new FragmentB(); getSupportFragmentManager().beginTransaction() .setReorderingAllowed(true) .setCustomAnimations(...) .addSharedElement(view, view.getTransitionName()) .replace(R.id.fragment_container, fragment) .addToBackStack(null) .commit();
Giriş geçişini ertelemek için parçanın onViewCreated()
yönteminde Fragment.postponeEnterTransition()
çağrısı yapın:
Kotlin
class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... postponeEnterTransition() } }
Java
public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... postponeEnterTransition(); } }
Verileri yükleyip geçişi başlatmaya hazır olduğunuzda Fragment.startPostponedEnterTransition()
numaralı telefonu arayın.
Aşağıdaki örnekte, paylaşılan bir ImageView
'ye resim yüklemek için Glide kitaplığı kullanılır ve ilgili geçiş resim yükleme tamamlanana kadar ertelenir.
Kotlin
class FragmentB : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... Glide.with(this) .load(url) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(...): Boolean { startPostponedEnterTransition() return false } override fun onResourceReady(...): Boolean { startPostponedEnterTransition() return false } }) .into(headerImage) } }
Java
public class FragmentB extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { ... Glide.with(this) .load(url) .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(...) { startPostponedEnterTransition(); return false; } @Override public boolean onResourceReady(...) { startPostponedEnterTransition(); return false; } }) .into(headerImage) } }
Kullanıcıların yavaş internet bağlantısı gibi sorunlarla uğraşırken tüm verilerin yüklenmesini beklemek yerine, ertelenmiş bir geçişin belirli bir süre sonra başlaması gerekebilir. Bu durumlarda, bunun yerine süreyi ve zaman birimini kullanarak parçanın onViewCreated()
yönteminde Fragment.postponeEnterTransition(long, TimeUnit)
çağrısı yapabilirsiniz. Ertelenen süre, belirlenen süre geçtikten sonra otomatik olarak başlar.
RecyclerView
ile paylaşılan öğe geçişleri kullanın
Ertelenen giriş geçişleri, giriş parçasındaki tüm görüntülemeler ölçülüp yerleştirilinceye kadar başlamamalıdır. RecyclerView
kullanırken geçişi başlatmadan önce tüm verilerin yüklenmesini ve RecyclerView
öğenin hazır olmasını beklemeniz gerekir. Aşağıda bununla ilgili bir örnek verilmiştir:
Kotlin
class FragmentA : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { postponeEnterTransition() // Wait for the data to load viewModel.data.observe(viewLifecycleOwner) { // Set the data on the RecyclerView adapter adapter.setData(it) // Start the transition once all views have been // measured and laid out (view.parent as? ViewGroup)?.doOnPreDraw { startPostponedEnterTransition() } } } }
Java
public class FragmentA extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { postponeEnterTransition(); final ViewGroup parentView = (ViewGroup) view.getParent(); // Wait for the data to load viewModel.getData() .observe(getViewLifecycleOwner(), new Observer<List<String>>() { @Override public void onChanged(List<String> list) { // Set the data on the RecyclerView adapter adapter.setData(it); // Start the transition once all views have been // measured and laid out parentView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw(){ parentView.getViewTreeObserver() .removeOnPreDrawListener(this); startPostponedEnterTransition(); return true; } }); } }); } }
Parça görünümünün üst öğesinde bir ViewTreeObserver.OnPreDrawListener
öğesinin ayarlandığına dikkat edin. Bunun amacı, parçanın tüm görünümlerinin ölçülüp yerleştirildiğinden ve dolayısıyla ertelenen giriş geçişine başlamadan önce çizilmeye hazır olduğundan emin olmaktır.
RecyclerView
ile paylaşılan öğe geçişlerini kullanırken dikkat edilmesi gereken bir diğer nokta da RecyclerView
öğesinin XML düzeninde geçiş adını ayarlayamayacağınız bir noktadır. Bunun nedeni, bu düzeni rastgele sayıda öğe paylaşmasıdır. Geçiş animasyonunun doğru görünümü kullanabilmesi için benzersiz bir geçiş adı atanmalıdır.
ViewHolder
bağlandığında her öğenin paylaşılan öğesine benzersiz bir geçiş adı atayabilirsiniz. Örneğin, her öğenin verileri benzersiz bir kimlik içeriyorsa bu kimlik, aşağıdaki örnekte gösterildiği gibi geçiş adı olarak kullanılabilir:
Kotlin
class ExampleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val image = itemView.findViewById<ImageView>(R.id.item_image) fun bind(id: String) { ViewCompat.setTransitionName(image, id) ... } }
Java
public class ExampleViewHolder extends RecyclerView.ViewHolder { private final ImageView image; ExampleViewHolder(View itemView) { super(itemView); image = itemView.findViewById(R.id.item_image); } public void bind(String id) { ViewCompat.setTransitionName(image, id); ... } }
Ek kaynaklar
Parça geçişleri hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara bakın.