Understanding Fragments in Android: Part 3

Written by azamatnurkhojayev | Published 2022/11/23
Tech Story Tags: android | android-app-development | androiddev | android-mobile-app | kotlin-mobile-development | android-development | android-tutorial | software-development

TLDRWe can define simple animations for transitions between fragments in the res/anim folder. But if we want to control any attributes of our fragment's view, we must specify animations in the res/animator folder.via the TL;DR App

In this article, we will analyze the interesting points of the animation Fragment API.

You can read the previous parts of the article at the link below.

We can define simple animations for transitions between fragments in the res/anim folder. But if we want to control any attributes of our fragment's view, we must specify animations in the res/animator folder. Moreover, we can easily combine them within a transaction.

fragmentManager.commit {
	setReorderingAllowed(true) 
	// Must be specified before add/replace otherwise they will be ignored
	setCustomAnimations( 
		R.animator.anim_enter, // InnerFragment appears on the screen
		R.anim.anim_exit, // OuterFragment goes off screen
		R.anim.anim_pop_enter, // OuterFragment returns to screen 
		R.animator.anim_pop_exit // InnerFragment goes off screen
		) 
		
		replace<InnerFragment>(R.id.container) 
		addToBackStack(null) 
	}

These animations are automatically applied to all subsequent transactions using this fragmentManager.

<!-- animator/anim_enter.xml --> 
<objectAnimator 
	xmlns:android="http://schemas.android.com/apk/res/android" 
	android:duration="400" 
	android:valueFrom="0" 
	android:valueTo="180" 
	android:propertyName="rotation" /> 
	
<!-- anim/anim_exit.xml --> 	
<alpha 
	xmlns:android="http://schemas.android.com/apk/res/android" 
	android:duration="400" 
	android:interpolator="@android:anim/decelerate_interpolator" 
	android:fromAlpha="1" 
	android:toAlpha="0" /> 
	
<!-- anim/anim_pop_enter.xml --> 
<alpha 
	xmlns:android="http://schemas.android.com/apk/res/android" 
	android:duration="400" 
	android:interpolator="@android:anim/decelerate_interpolator" 
	android:fromAlpha="0" 
	android:toAlpha="1" /> 
	
<!-- animator/anim_pop_exit.xml --> 
<objectAnimator 
	xmlns:android="http://schemas.android.com/apk/res/android" 
	android:duration="400" 
	android:valueFrom="180" 
	android:valueTo="360" 
	android:propertyName="rotation" />

If you do not want to prescribe each animation, you can use Transition - for example, prepared Fade (). It is specified in InnerFragment and overrides the animation in the transaction if one was specified.

// InnerFragment.kt 

override fun onCreate(savedInstanceState: Bundle?) { 
	super.onCreate(savedInstanceState) 
	// Animation when moving to the screen 
	enterTransition = Fade() 
	
	// Animation when leaving the screen via fragmentManager.popBackStack()
	// If not specified, will be used
	enterTransition exitTransition = Fade() 
	
	// Animation when exiting the screen is not via fragmentManager.popBackStack()
	// For example, via replace() 
	// If not specified, will be used
	enterTransition returnTransition = Fade() 
	
	// Animation when returning to the screen via
	fragmentManager.popBackStack()
	// If not specified, will be used
	enterTransition reenterTransition = Fade() 
	}

These are not yet the top animation features in the Fragment API. The next stage of development is the general transitions of elements, with the help of which you can get the implementation of the transition.

To create such an animation, we will use the FragmentTransaction.addSharedElement(View, String) method and the standard transition ChangeBounds().

First, we need to make the view elements we want to animate unique within the transitionName markup. This can be done through xml or in code. In InnerFragment we specify animations:

<!--- fragment_outer_layout.xml --> 
<TextView 
	android:id="@+id/textViewStart" 
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content" 
	android:text="Outer Fragment" 
	android:transitionName="text_start" /> 

<!--- fragment_inner_layout.xml --> 
<TextView 
	android:id="@+id/textViewDestination" 
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content" 
	android:text="Inner Fragment" 
	android:transitionName="text_destination" />

// OuterFragment.kt 
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 
	ViewCompat.setTransitionName(imageViewStart, "image_start") 
} 
	
// InnerFragment.kt 
override fun onCreate(savedInstanceState: Bundle?) { 
	super.onCreate(savedInstanceState) 
	// Animation when opening a fragment
	sharedElementEnterTransition = ChangeBounds() 
	
	// Animations when closing a fragment
	// If not specified, sharedElementEnterTransition will be used 
	sharedElementReturnTransition = ChangeBounds() 
} 
	
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 
	ViewCompat.setTransitionName(imageViewDestination, "image_destination") 
}

Вызываем транзакцию:

// OuterFragment.kt 
parentFragmentManager.commit { 
	setReorderingAllowed(true) 
	addSharedElement(imageViewStart, "image_destination") 
	addSharedElement(textViewStart, "text_destination") 
	replace<InnerFragment>(R.id.container) 
	addToBackStack(null) 
}

If all views are rendered synchronously, we can get the animation shown above just like that.

If we use a shared element transition with RecyclerView, then we need to remember that it draws its items after the screen layout is drawn. It turns out that the transition animation needs to be suspended until the list of items is ready to be drawn.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 
	// Pausing the transition
	postponeEnterTransition() 
	
	// Waiting for everything to load
	viewModel.data.observe(viewLifecycleOwner) { 
	// Passing data to RecyclerView adapter
	adapter.setData(it) 
	// We are waiting for all the elements to be ready for drawing, and start 
	// the animation 
	(view.parent as? ViewGroup)?.doOnPreDraw { 
		startPostponedEnterTransition() 
		} 
	} 
}

The postponeEnterTransition() method requires FragmentTransaction.setReorderingAllowed(true) to be used.

I will also attach a link to the official documentation from Google on Fragment animation here.


Written by azamatnurkhojayev | I'm an Android developer. Teaches courses at the programming school, and writes articles about development.
Published by HackerNoon on 2022/11/23