Android Animation: Frame-by-Frame Animations with AnimationDrawable in Kotlin

Frame-by-frame animation is a simple yet effective technique to bring life to your Android applications. It involves displaying a sequence of images (frames) in rapid succession to simulate movement or changes. In Android development, the AnimationDrawable class (and its XML representation, <animation-list>) allows developers to create these types of animations efficiently using XML configuration. This blog post will delve into creating frame-by-frame animations using AnimationDrawable in Kotlin with XML for Android applications.

Understanding Frame-by-Frame Animation

Frame-by-frame animation involves showing a series of distinct images (frames) rapidly, creating an illusion of motion. This type of animation is often used for simple animations such as a loading spinner, a character walking, or a blinking effect. The simplicity of the method allows for detailed control over each step of the animation, making it suitable for scenarios where precision is key.

Why Use AnimationDrawable?

AnimationDrawable is an Android class that extends Drawable. It enables the animation of multiple drawable resources in a sequential order. Defining animations via XML and AnimationDrawable offers several advantages:

  • Organization: Separates animation configuration from the activity or fragment logic, promoting cleaner code.
  • Maintainability: Easier to modify animation sequences and durations without altering Kotlin code.
  • Reusability: XML animations can be reused across different parts of an application.

Step-by-Step Guide to Creating Frame-by-Frame Animations

Step 1: Prepare Your Animation Frames

First, gather all the images that will form the animation sequence. These images should be consistently sized to avoid a jarring visual experience. Store these image files (PNG, JPG, etc.) in the res/drawable directory of your Android project.

Step 2: Define the Animation Sequence in XML

Create an XML file in the res/drawable directory. This file will define the animation sequence using the <animation-list> tag.

Example XML file (res/drawable/my_animation.xml):


<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/frame_1" android:duration="100" />
    <item android:drawable="@drawable/frame_2" android:duration="100" />
    <item android:drawable="@drawable/frame_3" android:duration="100" />
    <item android:drawable="@drawable/frame_4" android:duration="100" />
    <!-- Add more frames as needed -->
</animation-list>
  • <animation-list>: This is the root element defining the animation sequence.
    • android:oneshot="false": Specifies if the animation should loop continuously (false) or play only once (true).
  • <item>: Each <item> defines a frame in the animation.
    • android:drawable: Refers to the drawable resource ID for the frame.
    • android:duration: Specifies the duration (in milliseconds) for which the frame is displayed.

Step 3: Load and Start the Animation in Kotlin

In your Activity or Fragment, load the AnimationDrawable and start the animation.


import android.graphics.drawable.AnimationDrawable
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imageView: ImageView = findViewById(R.id.my_image_view)
        imageView.setBackgroundResource(R.drawable.my_animation)

        val animationDrawable = imageView.background as AnimationDrawable
        animationDrawable.start()
    }
}

Explanation:

  • Get a reference to the ImageView where the animation will be displayed.
  • Set the background of the ImageView to the XML animation drawable.
  • Cast the ImageView background to an AnimationDrawable.
  • Call start() on the AnimationDrawable to begin the animation.

Step 4: Update the Layout File

Make sure your layout file includes an ImageView element where the animation can be shown. Here’s an example:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/my_image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Best Practices and Tips

  • Optimize Images: Use optimized images to reduce the app’s size and memory footprint. Tools like TinyPNG can help compress images without significant quality loss.
  • Consistent Image Sizes: Ensure that all frames have the same dimensions to avoid unexpected scaling and positioning issues during animation.
  • Memory Management: For complex animations or long sequences, consider recycling bitmaps to reduce memory usage. However, this is generally less of a concern with modern devices and efficient resource management.
  • Control the Animation: You can control the animation programmatically. For instance, use stop() to halt the animation and selectDrawable(index) to select a specific frame.

// Stop the animation
animationDrawable.stop()

// Select a specific frame (e.g., the first frame)
animationDrawable.selectDrawable(0)

Example: Creating a Simple Loading Animation

Here’s an example of creating a simple loading animation using several images of a rotating circle.

  1. Prepare a series of images that show a rotating circle (e.g., loading_frame_1.png, loading_frame_2.png, loading_frame_3.png, loading_frame_4.png).
  2. Create an XML file named loading_animation.xml:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/loading_frame_1" android:duration="150" />
    <item android:drawable="@drawable/loading_frame_2" android:duration="150" />
    <item android:drawable="@drawable/loading_frame_3" android:duration="150" />
    <item android:drawable="@drawable/loading_frame_4" android:duration="150" />
</animation-list>
  1. Implement the animation in your activity:

import android.graphics.drawable.AnimationDrawable
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val loadingImageView: ImageView = findViewById(R.id.loading_image_view)
        loadingImageView.setBackgroundResource(R.drawable.loading_animation)

        val animationDrawable = loadingImageView.background as AnimationDrawable
        animationDrawable.start()
    }
}

Conclusion

Frame-by-frame animation using AnimationDrawable provides a straightforward method to create engaging visual effects in Android applications. By leveraging XML for defining animation sequences and controlling animations programmatically with Kotlin, developers can produce visually appealing and performant animations. Keep the animations lightweight, optimize resources, and manage the animations carefully to avoid potential performance issues and deliver a smooth user experience.