Stanford CS193p: iOS Development with SwiftUI | 2025 | L8: Animation Demonstration
By Unknown Author
Key Concepts
- Explicit Animation: Using
withAnimationto trigger animations. - Implicit Animation: Applying animations directly to views or bindings that automatically animate changes.
- Transitions: Animations that occur when views appear or disappear.
withAnimation: A SwiftUI function to explicitly animate state changes.transaction: A mechanism to control animation behavior during state changes.animation(_:value:): A view modifier for implicit animation.transition(_:): A view modifier for animating view appearance and disappearance.matchedGeometryEffect(id:in:): A view modifier for creating smooth transitions between views by matching their geometry.Group: A container view that doesn't affect layout but can be used to apply modifiers to multiple child views.- View Modifiers: Functions that modify the appearance or behavior of views.
- Extensions: Adding new functionality to existing types, like
Animation,AnyTransition, andView. @State: A property wrapper for managing view-specific mutable state.@Namespace: A property wrapper used withmatchedGeometryEffectto create a shared coordinate space for animations.
Animation in CodeBreaker
This lecture focuses on implementing and refining animations within the CodeBreaker application, building upon previous concepts of explicit and implicit animation. The goal is to create visually appealing and intuitive user experiences by controlling how elements appear, disappear, and change.
1. Refining Existing Animations and Custom Animations
- Slowing Down Animations: To better observe and fine-tune animations, all animations are intentionally slowed down to a 3-second duration. This is achieved by passing a custom
AnimationtowithAnimation, specificallyAnimation.easeInOut(duration: 3). - Custom Animation Constants: To manage animation configurations consistently, custom static let properties are added to the
Animationstruct. For example,Animation.guessis created to hold the specific animation used for the guess action. This allows for easy modification of animation parameters across the app. - Restart Animation: A
restartbutton is introduced, which triggers both a model restart and UI-specific resets. The restart action is also wrapped inwithAnimationto animate the UI changes. A commonCodeBreaker.animationis proposed for both guess and restart actions, but the flexibility to define separate animations for different actions is highlighted.
2. Animation Suppression and Transaction Control
- Problem: When the master code is revealed upon guessing correctly, there's a visual artifact where the hidden code obscuring the master code animates out, potentially revealing the code too early or creating an undesirable visual effect.
- Solution 1:
.animation(nil, value: ...): The.animation(nil, value: code.isHidden)modifier is applied to the view responsible for obscuring the master code. This explicitly disables animation for changes tocode.isHidden. - Problem with Solution 1: This approach also prevents the desired animation when the master code is revealed after a correct guess.
- Solution 2:
transaction: Thetransactionobject, accessible within awithAnimationblock, provides finer control. By checkingcode.isHiddenwithin the transaction, animation can be conditionally suppressed. Ifcode.isHiddenis true (meaning the code is about to be revealed),transaction.animationis set tonil. This ensures that the master code is revealed instantly whenisHiddenbecomes false, but other animations (like the guess action) still occur. - Distinction:
animation(nil, value:)suppresses animation for a specific value change, whiletransactionallows conditional suppression based on the current state within an animation block.
3. Transitions for View Appearance and Disappearance
- Peg Chooser Animation: The peg chooser at the bottom of the screen is designed to slide off when the game ends and slide back on when the game restarts, mimicking keyboard behavior.
- Initial Approach:
transition(.move(edge: .bottom)): This transition is applied to the peg chooser. - Problem: The safe area at the bottom of the screen prevents the peg chooser from fully disappearing off-screen.
- Solution:
transition(.offset(x: 0, y: 200)): An offset transition is used to move the peg chooser a specific distance (200 points) downwards. The positiveyvalue indicates downward movement in iOS coordinate systems. - Custom Transition Constants: Similar to animations, custom static let properties are created for transitions, such as
AnyTransition.pegChooserTransition, to manage and reuse transition configurations. - Asymmetric Transitions for Attempts: The attempts (feedback pegs) require different animations for appearing and disappearing.
- Removal: Pegs should fly off the right edge (
.move(edge: .trailing)). - Insertion: Pegs should appear from the top (
.move(edge: .top)). AnyTransition.asymmetric(insertion:removal:): This is used to define distinct animations for insertion and removal.
- Removal: Pegs should fly off the right edge (
- Conditional Transitions: The animation for attempts when the game is over needs to be different. Instead of moving, they should remain static or fade. This is achieved using a ternary operator within the transition definition:
isOver ? .opacity : .move(edge: .trailing). identityTransition: Theidentitytransition means no animation occurs, useful when views should appear or disappear instantly.- Fixing Peg Fading During Guess: When a guess is made, the pegs in the guess area fade out as they are cleared. This is undesirable. The
.animation(nil, value: game.attempts.count)modifier is applied to the guess view to prevent animation when the number of attempts changes (which happens when a guess is made or when restarting). - Two-Step Restart Animation: To prevent the guess area from appearing while attempts are sliding out during a restart, a two-step animation is implemented:
- A
@Statevariablerestartingis introduced. When restart is initiated,restartingis set totrue. - The guess view is made visible when
!game.isOver || restarting. This allows the guess to reappear. - A chained animation using
withAnimationis used. The first animation setsrestartingtotrue, allowing the guess to appear. Once this animation completes, the actual restart logic is executed, andrestartingis set back tofalse.
- A
- Hiding Guess During Restart Animation: To prevent the guess from appearing too early during the restart animation,
.opacity(0)is applied to the guess view whenrestartingis true. This makes the guess invisible until the appropriate time. - Fixing Marker Overlap: Markers (feedback pegs) appearing on top of the "Guess" button text is an issue. This is resolved by hiding the most recent markers initially using a
@StatevariablehidesMostRecentMarkers. The markers are then revealed with a slight delay after the guess animation completes.- A
showMarkerscomputed property is used to conditionally display markers based onhidesMostRecentMarkersand whether it's the most recent attempt.
- A
4. Code Organization and View Modifiers
- Refactoring Functions: Button actions like
guess()andrestart()are extracted into separate functions for better readability and organization. - Custom View Modifiers: A custom view modifier,
.flexibleSystemFont(), is created using an extension onView. This modifier encapsulates logic for setting flexible font sizes, making the code cleaner and more reusable. - UI Extensions File: All custom view modifiers and extensions are moved into a separate
UIExtensions.swiftfile for better project organization. - System Images for Buttons: Buttons can be enhanced with system images (e.g.,
arrow.circle.pathfor restart) that adapt to different contexts (like toolbars) usinglabelStyle.
5. Animating Selection
- Problem: The selection indicator jumps between pegs instead of sliding smoothly.
- Attempt 1: Animating a Binding: Applying
.animation(.selectionAnimation)directly to aBindingfor selection. This works for changes made through the binding but not for changes made directly within the view. - Attempt 2: Explicit Animation with
withAnimation: Wrapping selection changes inwithAnimationeverywhere. This is repetitive. - Attempt 3: Implicit Animation with
.animation(_:value:): Applying.animation(.selectionAnimation, value: selection)to the view that draws the selection. - Problem with Implicit Animation: This also animates the peg appearing, which is not desired.
- Solution:
Groupand.matchedGeometryEffect:Group: AGroupis introduced as a container for the selection shape. This provides a stable element to attach the.animationmodifier to, ensuring that only the selection's movement is animated, not the content within it..matchedGeometryEffect(id:in:): This modifier is applied to the selection shape. It allows the selection to smoothly transition between different positions by matching its geometry across views. A@Namespaceis used to create a shared coordinate space for this effect. Theidparameter identifies the element being matched, and thenamespaceensures that matches are only made within the same context.
6. Final Animation Tuning
- Default Animation: The slow animation duration is replaced with the default animation, which is typically much faster.
- Bouncy Animation: The
Animation.bouncy()option is demonstrated, showing a subtle overshoot and settle effect that can make animations feel less abrupt. - Choosing Animations: The lecture emphasizes that different animations can be chosen for different actions (guess, restart, selection) to achieve specific visual effects.
Conclusion
This lecture provides a deep dive into advanced animation techniques in SwiftUI, covering explicit and implicit animations, transitions, transaction control, and custom view modifiers. The focus is on creating polished and intuitive user experiences by carefully controlling how UI elements behave. Key takeaways include the importance of slowing down animations for debugging, using transaction for fine-grained control, understanding the nuances of view transitions, and leveraging matchedGeometryEffect for smooth geometric animations. The lecture also highlights best practices for code organization and the creation of reusable UI components.
Chat with this Video
AI-PoweredLoad the transcript when you're ready to chat so the initial page stays lighter.
Related Videos

Apple to Add AI-Powered Photo-Editing Tools
Bloomberg Technology

This idea validation formula has made him $500K from iOS apps
Starter Story

Dumb iPhone Apps Are Making People Rich Again (Here’s how)
My First Million

Stanford CS193p: iOS Development with SwiftUI | 2025 | L13: SwiftData
Stanford Online

Stanford CS193p: iOS Development with SwiftUI | 2025 | L16: Shapes, Gestures, Persistence
Stanford Online

Stanford CS193p: iOS Development with SwiftUI | 2025 | L14: SwiftData Demonstration
Stanford Online

Stanford CS193p: iOS Development with SwiftUI | 2025 | L15: Multithreading
Stanford Online