How Do SwiftUI Animations Work? Stanford CS193p Spring 2021 Lecture 8 Animation Demonstration

June 7, 2021
by
Stanford
YouTube video player
How Do SwiftUI Animations Work? Stanford CS193p Spring 2021 Lecture 8 Animation Demonstration

TL;DR

SwiftUI can animate changes explicitly by placing a model-changing Intent, such as shuffling cards, inside withAnimation. In the Memorize game, this causes the positioning and framing modifiers used by LazyVGrid to move cards smoothly instead of making them jump across the screen. The demonstration also connects implicit animation, transitions, custom modifiers, geometry matching, and zIndex, so read on for how each technique fits into the interface.

Transcript

(upbeat music) - [Announcer] Stanford University. - [Instructor] Okay, it's demo time. Lecture 8 of Stanford CS193p, Spring of 2021. We talked all about animations in the last lecture. We ended it with a demo of implicit animations, but a much more common case for doing animation is explicit animation. And to show that, I'm going to add a feature t... Read More

Key Insights

  • Intent separates UI and model: The Shuffle button does not mutate the card collection directly. It calls the shuffle Intent on the game ViewModel, which asks the Model to execute its mutating shuffle function. This preserves the structure used by the Memorize app while still giving the View a simple action to invoke.
  • One call randomizes the cards: The Model implementation of shuffle is deliberately small, using cards.shuffle to rearrange the collection. The same operation can run when the game is created as well as when the user presses Shuffle. Initial shuffling removes the easy arrangement in which matching cards appear next to one another.
  • Factoring clarifies the body: Extracting the card interface into gameBody and the control into a separate shuffle-button View makes the main body a concise VStack. This refactoring is demonstrated alongside animation work because it creates an obvious location for the button and keeps its action, label, and relationship to the game content understandable.
  • Clear color reserves layout space: Color.clear can replace a transparent Rectangle when AspectVGrid needs a placeholder for a discarded card. Although the color is see-through, it still participates as a View in the layout context. This lets the grid retain the required space without drawing a visible card or constructing an explicit Rectangle.
  • Paths can render directly: A Path is not limited to serving as internal data for a custom Shape. The lecture explains that a path can be built through operations such as moving and adding a line, placed directly where a View is expected, and then stroked or filled. This parallels the way Color can act as a View.
  • Unanimated changes expose discontinuity: Before withAnimation is added, the shuffle function works correctly, but the cards jump immediately between grid locations. The awkward result distinguishes a valid model update from a polished visual transition. Animation does not create the shuffle itself. It presents the already-requested rearrangement as continuous movement.
  • Explicit animation wraps the cause: The instructor places the shuffle request inside withAnimation, a function that receives a no-argument, no-result function. The important boundary is the state-changing operation inside that closure. SwiftUI observes the resulting interface changes and animates the relevant animatable values rather than requiring movement instructions for every card.
  • Layout modifiers drive movement: The card movement comes from modifiers used by layout containers, particularly position and frame behavior inside AspectVGrid and LazyVGrid. Those modifiers determine where Views appear and how large they are. Because their values can animate, SwiftUI can interpolate from each card’s old placement to its new shuffled placement.
  • Card Shapes stay unchanged: The visible cards contain Shapes, but the shuffle does not animate those Shapes directly. What changes is the placement of the surrounding Views. This distinction explains why the animation succeeds even though no custom Shape animation is written: the animatable values belong to the layout modifiers that reposition and size the Views.
  • Animations accept interruption: Repeatedly tapping Shuffle before one movement finishes does not require manual cancellation logic in the demonstration. The current animation is interrupted and SwiftUI continues toward the newly requested arrangement as well as it can. This behavior makes rapid model changes feel continuous, although the instructor notes that some situations are difficult for the framework to resolve.
  • Timing reveals interpolation: The default shuffle animation moves quickly, so the instructor changes it to easeInOut with a duration of five seconds. Slowing the transition makes the intermediate motion easier to observe. It also demonstrates that an explicit animation can specify both its timing curve and duration while wrapping the same model-changing Intent.
  • Different tools solve different changes: The existing analysis distinguishes movement and property changes from insertion, removal, custom interpolation, geometry coordination, and depth ordering. withAnimation and implicit animation animate changing values, transitions govern appearance and disappearance, AnimatableModifier supports custom effects, matchedGeometryEffect coordinates geometry, and zIndex explicitly controls which View occupies the higher visual layer.

Explore YouTube Video Summarizer or Get YouTube Transcript Extractor

Questions & Answers

Q: How can explicit animation be implemented in SwiftUI?

Wrap the state-changing operation in withAnimation. In the lecture, the Shuffle button calls the game ViewModel’s shuffle Intent inside that function. The Model rearranges the cards, and SwiftUI animates the affected animatable ViewModifiers as the interface updates. This works because the closure identifies the change whose resulting visual differences should be animated.

Q: Why do the Memorize cards animate when shuffled?

The shuffled cards receive new positions in the grid after the Model rearranges the collection. Container Views, including LazyVGrid, use position and frame modifiers to place and size those card Views. Because the shuffle occurs inside withAnimation, changes to those animatable modifier values are interpolated. The cards therefore travel smoothly between placements instead of jumping immediately.

Q: How is the Shuffle button connected to the Model?

The button asks the game ViewModel to perform a shuffle Intent. That Intent delegates the operation to a mutating shuffle function in the Model. The Model function calls cards.shuffle to rearrange the card collection. This chain lets the View request gameplay behavior without directly editing the Model’s cards.

Q: What happens if Shuffle is tapped during an animation?

The current card movement can be interrupted automatically. When another shuffle begins halfway through the first one, SwiftUI starts continuing toward the newly requested arrangement from the animation’s current state. The lecture describes this interruptibility as a valuable property of animation. SwiftUI handles the continuation as well as it can, though some changes may be difficult to reconcile.

Q: How can an animated View transition be performed in SwiftUI?

Use the .transition() modifier to describe how a View appears or disappears. The existing analysis identifies transition forms such as scale and opacity. An asymmetric transition can assign different behavior to insertion and removal. The transition defines the visual change, while an animation context makes that appearance or disappearance animate.

Q: What is AnimatableModifier used for in SwiftUI?

AnimatableModifier supports custom animation effects for Views. A custom modifier conforms to the protocol and supplies the required animatableData property. SwiftUI can then interpolate that data as the animation progresses. This is useful when the desired effect is not fully expressed by the standard modifiers demonstrated elsewhere in the lecture.

Q: How can View order be controlled in a SwiftUI ZStack?

A ZStack normally layers its Views according to their order, with the last added View on top and the first on the bottom. Apply .zIndex() when that default order does not produce the intended visual result. The modifier explicitly assigns ordering along the z-axis. This matters during animation when moving or transitioning Views must remain above or below other content.

Q: Why use Color.clear in the card grid?

Color.clear fills a layout position without displaying a visible color. In the Memorize interface, it can occupy the AspectVGrid space belonging to a card that was matched, turned down, and discarded. A Color can behave like a View in this context, effectively providing a color-filled rectangle. Using the clear color preserves the needed layout space while keeping that location visually empty.

Summary & Key Takeaways

  • Building the shuffle feature: Stanford CS193p Lecture 8 begins by adding a Shuffle button to the Memorize game. Because the View needs a way to request this change, the instructor adds a shuffle Intent to the ViewModel and a mutating shuffle function to the Model. That function calls cards.shuffle. The cards can also be shuffled when the game is first created, preventing matching cards from remaining conveniently side by side and making gameplay more difficult.

  • Restructuring the game interface: The instructor factors the existing game content into a computed View called gameBody, then creates another View for the shuffle button. The button is labeled “Shuffle,” and its action asks the game ViewModel to perform the shuffle Intent. The main body becomes a VStack containing gameBody and the button. Padding is applied in every direction to create space between the game, the button, and the edges of the screen.

  • Using values as Views: While reorganizing the interface, the lecture replaces a clear Rectangle with Color.clear to occupy an empty location in AspectVGrid after a matched card has been discarded. A Color can behave as a View in the appropriate context, effectively producing a rectangle filled with that color. The instructor also notes that Path can behave as a View, allowing a constructed path to be inserted directly and then stroked or filled.

  • Animating shuffled card positions: Without animation, shuffled cards abruptly jump around the screen. Wrapping the ViewModel’s shuffle request in withAnimation makes their movement smooth. The animation works because SwiftUI animates animatable Shapes and ViewModifiers. Here, the card Shapes are not themselves changing. Instead, container Views such as LazyVGrid use position and frame modifiers to place and size the card Views, and those animatable modifiers interpolate when the model change occurs inside withAnimation.

  • Extending SwiftUI animation control: The broader demonstration covers implicit and explicit animation, rotationEffect, scaleEffect, rotation3DEffect, and transitions for Views that appear or disappear. It also introduces AnimatableModifier for custom effects, matchedGeometryEffect for coordinated geometry changes, and zIndex for explicit depth ordering. The shuffle example additionally shows that an animation can be interrupted: tapping Shuffle again midway starts another movement from the current state, while an easeInOut animation can be assigned a five-second duration for inspection.


Read in Other Languages (beta)

Share This Summary 📚

Explore More Summaries from Stanford 📚