Overview

Chapter 13. Transitions with Rx

This chapter explains how to drive UI transitions with RxJava by treating animations as data streams, shifting from fire-and-forget effects to smooth, interruptible, and stateful transitions. It reframes UI state as a continuum—expressed as a ratio from 0.0 to 1.0—so views can render any in‑between state while view models orchestrate progression. The result is cleaner separation of concerns, more testable logic, and higher perceived quality under rapid or unpredictable user input.

The chapter introduces reactive parametrization: views become “dumb” consumers that redraw according to a single float (openRatio), while view models emit those values. A custom “fan” widget illustrates the approach: a ViewGroup computes per‑child transforms (angles and rotation centers) and exposes a setOpenRatio(r) that scales geometry by the ratio, enabling partial openness without the view knowing about animation. The same ratio also drives related UI, such as dimming a background by mapping the ratio to an alpha value, demonstrating how one source of truth can coordinate multiple visual effects.

On the view‑model side, user clicks toggle a Boolean target (isOpen), which is mapped to 0 or 1 and then transformed into a smooth sequence using an animateTo operator. This operator isn’t built in; it’s implemented with ValueAnimator to interpolate from the current ratio to the target, canceling any ongoing animation and always starting from the latest state to avoid glitches and queues. The key takeaways are to represent transition progress as a single parametrized value, keep rendering logic in the view and timing/state logic in the view model, and handle rapid input robustly. The technique generalizes to many components, and can be refined further with easing and other parametrizations.

FAQ

What is the “fire-and-forget” animation strategy and when does it break down?Fire-and-forget means you start an animation and let it finish regardless of new input. It works for short animations (roughly under 300 ms). For longer ones, rapid user actions or external state changes can force a new transition before the old one ends, causing visible glitches (jumps in state).
Why shouldn’t UI state be modeled as just true/false?Animated UI often lives in between states, so a boolean can’t capture progress. Represent state with a continuous value (for example, a ratio from 0.0 to 1.0), which lets you render partial progress and resume animations smoothly from the current point rather than snapping.
How do I avoid glitches when a new transition starts mid-animation?Always start the new animation from the current progress, not from 0 or 1. Cancel any ongoing animation, then animate from “current ratio” toward the new target (0.0 or 1.0). Keeping and emitting the live progress value is the key to seamless transitions.
Where should animation logic live: in the view or the view model?Prefer pushing complex, long-running, or multi-view animations into the view model for better testability and coordination (for example, driving both a widget and a dimmer). Keep the view “dumb” and parametrized so it only renders given ratios; it doesn’t need to know about animation itself.
What is reactive parametrization and how does it apply to the FanView?Reactive parametrization means the view exposes a parameter (like openRatio in 0.0–1.0) and redraws based on that value. The view model emits an Observable of that parameter. The view simply subscribes and rerenders; animation is just the view model emitting many in-between values over time.
How are the FanView child transformations calculated?Each item’s rotation is index × 20 degrees, with the header at 0 degrees. The rotation center is at half the child’s height (x = y = height/2). Reverse the indexing if needed to keep the header drawn on top while the other items fan out beneath.
What does the animateTo operator represent, and how is it realized on Android?Conceptually, animateTo turns abrupt value changes into smooth transitions from the current to the target value. On Android, you implement it yourself using ValueAnimator: cancel any running animator, create a new one from lastValue to targetValue, emit updates on each frame, and run it on the main thread.
How do clicks drive open/close and produce openRatio in the view model?Clicks toggle a Boolean isOpen in a BehaviorSubject. Map isOpen to target ratios (true → 1.0, false → 0.0), then pass that through the animateTo operator to get a smoothly changing Observable openRatio. Expose openRatio for the view to subscribe to.
How can I dim the background in sync with the fan animation?Subscribe to the same openRatio stream and map it to an alpha value (for example, 0–64 or up to 255). Apply that alpha to the background/dimmer drawable on the main thread. The dimmer will fade in and out perfectly in step with the fan’s openness.
Should I queue transitions instead of interrupting them?Queuing (waiting for one animation to finish before starting the next) is rarely desirable for interactive UI on Android and lacks native support. Users expect immediate response; it’s typically better to cancel the current animation and continue from the current progress toward the new target.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • RxJava for Android Developers ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • RxJava for Android Developers ebook for free