Welcome! In this part, we'll walk through setting up your animations in Rive and a high-level approach to the implementation. Subsequent parts will detail the integration across iOS, Android, and Flutter. Feel free to jump straight from this section to your desired platform. You can find links to each at the end.

The projects for each of the platforms are also available on GitHub:
Flutter - iOS - Android

About Rive

If you're already familiar with Rive, you might want to jump ahead, if not, here's a quick intro – Rive is a real-time, interactive design tool that allows you to design, animate, and integrate your assets into any platform via our runtimes.

At its core, Rive is formed of two parts — the editor, and the runtimes. If you’re familiar with other design and animation tools, then you’ll feel right at home with Rive. Our editor provides the tools necessary to create, animate, and collaborate on your apps and games.

Rive runtimes provide the means to play and interact with your animations in real-time. They're optimised for size, designed for control, and entirely open-source. Currently, we have runtimes for the web, Flutter, iOS, Android, and C++, with more on the way. Learn more about them here.

Getting started

In this example, we've created a number of planets directly within Rive. However, if you already have assets, or prefer another design tool, you can import SVGs into Rive ready for animating.

Due to their relative simplicity, I won't go into the specifics of creating the planets themselves, however it's worth noting that I've nested certain shapes within an empty group for an additional transform space. One example of this is the moon, whereby an inner group offsets the x position, whilst the outer group controls the rotation from the centre of the artboard for a tilt effect. This isolates aspects I may want to animate without being destructive to others. Stay tuned for upcoming features that will help make this process more intuitive!

You'll notice that all my planets are stacked on top of each other right now. That's by design, as it keeps things neat while we're in design mode. The position of the planets will be controlled by the animations.

Once you're done creating or importing your assets, its time to hop over into animate mode via the upper right-hand toggle, or by hitting tab.

Animation states

It's important to consider how best to breakup the overall animation in order for different states to be controlled at runtime. Here, we've split the interaction into four different animations. Which ones play and when will be managed at runtime, though it's worth mentioning that in future you'll be able to handle that right from within the editor as well!

Idle – A looping animation that plays continuously throughout all stages of the refresh. In this case, stars, comets, and the earth are animating. Although this animation appears to show the other planets directly behind the earth, their position will be translated by the pull animation.

Pull – A one-shot animation that adjusts the position and scale of planets to create a zoom effect. Rather than progress this animation every frame, we'll map the user’s drag position to its duration to increase the zoom amount as the user pulls down and vice versa.

Trigger – A one-shot animation that plays once the user drags to a threshold that triggers the refresh. It acts as visual feedback for the user, prompting them that the refresh has initiated. Here, the earth bounces briefly.

Loading – A looping animation that plays continuously once the refresh has been triggered and until it has completed. In this case, the moon orbits around the earth repeatedly.

With all of our animations setup, it's time to export the file ready to implement into our app!

Implementing into an app

We've included examples demonstrating how to implement our pull-to-refresh animation across iOS, Android, and Flutter. Before jumping to whichever you're most interested in, it's worth briefly going over some of the principles that are shared across them.

Broadly speaking, there are three main functions we want to manage:


We'll start by creating a controller that will be responsible for setting up and managing the animations. It'll include a handful of class variables, most notably the four animation instances and the artboard. Other values may include the scroll position, the trigger threshold, and the refresh state, however these will vary across platforms. Upon loading the .riv file, we'll grab each of the four animations we created earlier and assign them to the aforementioned variables.


The Rive runtimes are designed to provide the greatest level of control over your animations, and subsequently we'll manage what's happening within the run loop that is called every frame. We'll structure the loop to control the playback of each of the four animations based on the refresh state. Loosely speaking, that will:

  1. Continually advance the idle animation, regardless of the state of refreshing.
  2. Map the drag position to the duration of the pull animation before a refresh is triggered.
  3. Play the trigger animation once the drag position reaches the given threshold.
  4. Once the trigger animation has completed, loop the loading animation until the refresh has finished.


Upon the completion of a refresh cycle, we'll reset animations to the beginning, ready for the next refresh.

Now its time to dive into the runtimes! We'll start with Flutter, however if you'd prefer to jump straight to another platform, you can select it from the links below...

Part 2 - Flutter
Part 3 - iOS
Part 4 - Android