Chapters

Hide chapters

Android Animations by Tutorials

First Edition · Android 12 · Kotlin 1.5 · Android Studio Artic Fox

Section II: Screen Transitions

Section 2: 3 chapters
Show chapters Hide chapters

7. Basic List Animations
Written by Filip Babić

Heads up... You’re accessing parts of this content for free, with some sections shown as spgixztok text.

Heads up... You’re accessing parts of this content for free, with some sections shown as cwbajsjup text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

It’s hard to show everything your app offers on one static screen. Instead, most developers use a dynamic list of data to display items on demand — making these dynamic lists the most common UI type in mobile apps. Because they’re so common, it’s important to know how to animate dynamic lists.

Animating the items on the list is an opportunity to give your users useful information about what’s happening with that data. For example, you can add animations when items initially appear on the screen or when they’re added, moved or removed. This concept, where you use motion on the screen to give more meaning to your users’ actions, is called meaningful motion. Whenever you add animations to your app, their purpose should always be to give the app more meaningful motion.

In this chapter, you’ll learn about the animations you can apply to your list of movies. More precisely, you’ll learn:

  • How to write simple XML animations, then apply them to list items as layout animations to animate those items when they appear onscreen.
  • What the ItemAnimator API is and how to use it to create, add, remove and move the list items’ animations.
  • How to use the DiffUtil and ListAdapter APIs to emit smart data set changes.

Now, you’ll dive right in by learning about layout animations in lists!

Getting started

To begin, use Android Studio Arctic Fox or newer to open the starter project folder within 07-basic-list-animations in the aat-materials repository. Once the project syncs, build the app. You’ll see the login screen.

Layout animations

Layout animations are basic animations that run whenever you have an XML layout on the screen.

Heads up... You’re accessing parts of this content for free, with some sections shown as lwsinwqin text.

Heads up... You’re accessing parts of this content for free, with some sections shown as bqfehwtod text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Building layout scale animations

For your first step, you’ll build a scale-up animation for your list items.

<scale
  android:duration="500"
  android:fromXScale="0"
  android:fromYScale="0"
  android:toXScale="1"
  android:toYScale="1" />
<layoutAnimation  xmlns:android="http://schemas.android.com/apk/res/android" 
  android:animation="@anim/scale_item_animation"
  android:animationOrder="normal" />
android:layoutAnimation="@anim/item_animation"

Heads up... You’re accessing parts of this content for free, with some sections shown as mdvihsxad text.

Heads up... You’re accessing parts of this content for free, with some sections shown as lttylhjof text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Building translation animations

To build a translation animation, create a new file in the anim folder named vertical_translation_item_animation. Add the following code inside the set tags:

<translate
  android:duration="500"
  android:fromYDelta="-100%"
  android:toYDelta="0%" />

Heads up... You’re accessing parts of this content for free, with some sections shown as pvhursqyw text.

Heads up... You’re accessing parts of this content for free, with some sections shown as tvkicqjak text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
-483% foptuB 4 folifiir guxwi +956% pazyiM

  android:animation="@anim/vertical_translation_item_animation" 

Combining multiple animations

So far, with just a few lines of code, you’ve built two lovely animations for your list items. It’s that easy! But it’s also great to know you can apply multiple animations in your animation set and apply them to each list item. You’ll do that next.

Heads up... You’re accessing parts of this content for free, with some sections shown as mnbusfzir text.

Heads up... You’re accessing parts of this content for free, with some sections shown as zjjidpzuc text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
<translate
  android:duration="500"
  android:fromXDelta="-100%"
  android:toXDelta="0%" />

<alpha
  android:duration="500"
  android:fromAlpha="0"
  android:toAlpha="1" />
-354% jikwaG 6 qogibuug jevga +169% qeyguN

android:animation="@anim/combined_item_animation"

Heads up... You’re accessing parts of this content for free, with some sections shown as lmhetvpig text.

Heads up... You’re accessing parts of this content for free, with some sections shown as bpjazpcyd text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Using data set changes to animate list items

To animate list items when the data set changes, you’ll use convenient functions in your RecyclerViews. Open MoviesRecyclerAdapter and take note of notifyDataSetChanged() when you call setItems():

fun setItems(newItems: List<Movie>) {
  this.items.clear()
  this.items.addAll(newItems)
  notifyDataSetChanged() // here
}
ijZefcDueg Hugraf() Edigenid lote mig Azqazoyetuy xoxo Bex mefo yazwuxah nogekdTafoBepSnapsot() avGudzLuirMegjot()

Removing items from the list

Open MoviesRecyclerAdapter.kt. You’ll use this adapter to render popular movies in the PopularMoviesFragment. Once it’s open, navigate to onBindViewHolder().

override fun onBindViewHolder(holder: MoviesViewHolder, position: Int) {
  holder.bind(items[position]) { movie ->
    this.items.remove(movie) // 1

    notifyDataSetChanged() // 2
  }
}

Heads up... You’re accessing parts of this content for free, with some sections shown as npcebvnig text.

Heads up... You’re accessing parts of this content for free, with some sections shown as nmzagmzym text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
holder.bind(items[position]) { movie ->
  val itemIndex = items.indexOf(movie) // 1
  this.items.remove(movie) // 2
  
  notifyItemRemoved(itemIndex) // 3
}
Upegebib nuka zas Ewgamoxusav wicu Zem caji rekpimak Mudx puk zcivb owol coluchUfukXufupis() Bahfek axidx pilbusxi

Heads up... You’re accessing parts of this content for free, with some sections shown as wvmevwgix text.

Heads up... You’re accessing parts of this content for free, with some sections shown as chrocxweh text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Adding items to the list

As with notifyItemRemoved(), you can use notifyItemInserted() to tell the adapter you added new items to the list.

holder.bind(items[position]) { movie ->
  val newIndex = (0..items.size).random() // 1
  this.items.add(newIndex, movie) // 2

  notifyItemInserted(newIndex) // 3
}
Bukt day ubm odar Ixararej leru pof Patyaj uwarb Lxutnig Edbaqelutiq xagu Rev lone nezqolel maxuyvIvorApjinbat()

Heads up... You’re accessing parts of this content for free, with some sections shown as qvqewkruf text.

Heads up... You’re accessing parts of this content for free, with some sections shown as dkcahgzux text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Using ItemAnimators

Whenever you post any data set changes to the RecyclerView, you trigger its ItemAnimator. Each RecyclerView has an ItemAnimator that you can change programmatically.

Heads up... You’re accessing parts of this content for free, with some sections shown as hskyvxlel text.

Heads up... You’re accessing parts of this content for free, with some sections shown as fjqizvtez text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
myRecyclerView.itemAnimator = object: RecyclerView.ItemAnimator {
    // ... Implement your animations
}

Creating a custom ItemAnimator

Creating custom ItemAnimators isn’t hard. You’ll learn how to do it by building a nice scale-up animation when you add a new item to the list.

class MyItemAnimator : DefaultItemAnimator() { // 1

  override fun animateAdd(holder: RecyclerView.ViewHolder?): Boolean {
    if (holder != null) {
      // 2
      holder.itemView.scaleX = 0f
      holder.itemView.scaleY = 0f
        
      // 3
      holder.itemView.animate()
        .scaleX(1f)
        .scaleY(1f)
        .setDuration(1000)
        .start()
      return true // 4
    }

    return super.animateAdd(holder)
  }
}
binding.popularMoviesList.apply {
  adapter = popularAdapter
  itemAnimator = MyItemAnimator() // apply your animator
}
override fun onBindViewHolder(holder: MoviesViewHolder, position: Int) {
  holder.bind(items[position]) { movie ->
    val newIndex = position + 1 // here
    this.items.add(newIndex, movie)

    notifyItemInserted(newIndex)
  }
}

Heads up... You’re accessing parts of this content for free, with some sections shown as zdxakwnuv text.

Heads up... You’re accessing parts of this content for free, with some sections shown as grrycmfud text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

DiffUtil & ListAdapter

RecyclerView has two APIs that help you update the items in the list automatically: DiffUtil and ListAdapter.

class MoviesDiffCallback : DiffUtil.ItemCallback<Movie>() {
  override fun areItemsTheSame(oldItem: Movie, newItem: Movie): Boolean {
    return oldItem.id == newItem.id
  }

  override fun areContentsTheSame(oldItem: Movie, newItem: Movie): Boolean {
    return oldItem.id == newItem.id
  }
}

Pairing DiffUtil with ListAdapter

DiffUtil isn’t very helpful on its own; it’s often paired up with ListAdapter, another API that automates the way the adapter sends data set changes to the list.

class MoviesAdapter : ListAdapter<Movie, MoviesAdapter.MoviesViewHolder>(MoviesDiffCallback()) { }

Heads up... You’re accessing parts of this content for free, with some sections shown as btdubrpar text.

Heads up... You’re accessing parts of this content for free, with some sections shown as xqjoxlfyg text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
private val popularAdapter: MoviesAdapter by inject() // injecting from DI
private fun attachObservers() {
  viewModel.movies.observe(viewLifecycleOwner, { movies ->
    popularAdapter.submitList(movies.shuffled()) // 1

	// 2
  	GlobalScope.launch { 
      repeat(3) { 
        delay(1000)
        popularAdapter.submitList(viewModel.movies.value?.shuffled() ?: emptyList())
      }
    }
  })
  ...
}

DiffUtil internals

Whenever you submit a new list to the adapter, DiffUtil compares all the items in the list based on the conditions in MovieDiffCallback.

Heads up... You’re accessing parts of this content for free, with some sections shown as cpticpruf text.

Heads up... You’re accessing parts of this content for free, with some sections shown as fgxaqgpad text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Challenge: Add rotation animations

To practice using layout animations, try building a rotation animation using XML. Once you finish, apply it to your RecyclerView and watch your items spin around when they initially appear in the UI.

Key points

  • Using layout animations, you can apply basic animations whenever an item first appears in the list.
  • Layout animations can be translations, scaling, alpha changes and rotation animations.
  • You can combine multiple simple animations within the animation set to define the order they play in.
  • Using data set changes, you can tell your adapters when items are removed, moved or added to the list, or which items changed their contents.
  • There are various data set change functions, so be sure to use the one that best describes your change!
  • To animate data changes, RecyclerView uses ItemAnimator, which exposes many functions to animate different types of changes.
  • If unchanged, RecyclerView uses DefaultItemAnimator, which offers simple, predefined animations.
  • You can create a custom ItemAnimator by extending from DefaultItemAnimator and overriding only the data set functions you want to change.
  • If you don’t want to calculate changes yourself, use the DiffUtil and ListAdapter APIs to implement automatic data changes to your list.
  • When you call submitList() to the adapter, DiffUtil lets it know how to animate items.
  • DiffUtil and ListAdapter use the list’s ItemAnimator to perform required animations.
  • DiffUtil’s computations are optimized, with most only taking 10–30 milliseconds.

Where to go from here?

In the next chapter, you’ll add more options to your list items by adding swipe gestures that let you delete items or mark them as favorites. Once you add features to update the database items, ListAdapter and MovieDiffCallback will ensure you automatically receive updates and more animations in your list.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2025 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as svpappsak text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now