- Install
- Set up an editor
- Test drive
- Write your first Flutter app, part 1
- Learn more
- Flutter for Android developers
- Flutter for iOS developers
- Flutter for React Native developers
- Flutter for web developers
- Flutter for Xamarin.Forms developers
- Introduction to declarative UI
- Cookbook
- Codelabs
- Tutorials
- User interface
- Introduction to widgets
- Layouts in Flutter
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Introduction to animations
- Animations overview
- Animations tutorial
- Hero Animations
- Staggered Animations
- Advanced UI
- Slivers
- Taps, drags, and other gestures
- Widget catalog
- Data & backend
- State management
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Firebase
- Accessibility & internationalization
- Accessibility
- Internationalizing Flutter apps
- Platform integration
- Writing custom platform-specific code
- Packages & plugins
- Using packages
- Developing packages & plugins
- Background processes
- Tools & techniques
- Android Studio / IntelliJ
- Visual Studio Code
- Upgrading Flutter
- Hot reload
- Code formatting
- Debugging Flutter apps
- Using OEM debuggers
- Flutter's build modes
- Testing Flutter apps
- Performance best practices
- Flutter performance profiling
- Creating flavors for Flutter
- Preparing an Android App for Release
- Preparing an iOS App for Release
- Continuous Delivery using fastlane with Flutter
- Bootstrap into Dart
- Inside Flutter
- Platform specific behaviors and adaptations
- Technical Overview
- Technical videos
- FAQ
- Flutter widget index
- Install
- Windows install
- MacOS install
- Linux install
- Set up an editor
- Write your first Flutter app, part 1
- Learn more
- Cupertino (iOS-style) widgets
- Layout widgets
- Animation and motion widgets
- Retrieve the value of a text field
- Basic widgets
- Material Components widgets
- Animate the properties of a Container
- Fade a Widget in and out
- Add a Drawer to a screen
- Displaying SnackBars
- Exporting fonts from a package
- Updating the UI based on orientation
- Using Themes to share colors and font styles
- Using custom fonts
- Working with Tabs
- Building a form with validation
- Create and style a text field
- Focus on a Text Field
- Handling changes to a text field
- Retrieve the value of a text field
- Adding Material Touch Ripples
- Handling Taps
- Implement Swipe to Dismiss
- Display images from the internet
- Fade in images with a placeholder
- Working with cached images
- Basic List
- Create a horizontal list
- Creating a Grid List
- Creating lists with different types of items
- Place a floating app bar above a list
- Working with long lists
- Report errors to a service
- Animating a Widget across screens
- Navigate to a new screen and back
- Navigate with named routes
- Pass arguments to a named route
- Return data from a screen
- Send data to a new screen
- Fetch data from the internet
- Making authenticated requests
- Parsing JSON in the background
- Working with WebSockets
- Persist data with SQLite
- Reading and Writing Files
- Storing key-value data on disk
- Play and pause a video
- Take a picture using the Camera
- An introduction to integration testing
- Performance profiling
- Scrolling
- An introduction to unit testing
- Mock dependencies using Mockito
- An introduction to widget testing
- Finding widgets
- Tapping, dragging and entering text
- Development
- Introduction to widgets
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Navigate to a new screen and back
- Send data to a new screen
- Return data from a screen
- Navigate with named routes
- Animating a Widget across screens
- AnimatedList
- Sample App Catalog
- Animations overview
- Animations tutorial
- Staggered Animations
- Slivers
- Taps, drags, and other gestures
- Accessibility widgets
- Assets, images, and icon widgets
- Async widgets
- Input widgets
- Interaction model widgets
- Painting and effect widgets
- Scrolling widgets
- Styling widgets
- Text widgets
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Accessibility
- Internationalizing Flutter apps
- Writing custom platform-specific code
- Using packages
- Fetch data from the internet
- Developing packages & plugins
- Background processes
- Android Studio / IntelliJ
- Set up an editor
- Flutter inspector
- Creating Useful Bug Reports
- Visual Studio Code
- Set up an editor
- Upgrading Flutter
- Hot reload
- Code formatting
Staggered Animations
Staggered animations are a straightforward concept: visual changes happen as a series of operations, rather than all at once. The animation might be purely sequential, with one change occuring after the next, or it might partially or completely overlap. It might also have gaps, where no changes occur.
This guide shows how to build a staggered animation in Flutter.
The following video demonstrates the animation performed by basic_staggered_animation:
In the video, you see the following animation of a single widget, which begins as a bordered blue square with slightly rounded corners. The square runs through changes in the following order:
- Fades in
- Widens
- Becomes taller while moving upwards
- Transforms into a bordered circle
- Changes color to orange
After running forward, the animation runs in reverse.
Basic structure of a staggered animation
The following diagram shows the Intervals used in the basic_staggered_animation example. You might notice the following characteristics:
- The opacity changes during the first 10% of the timeline.
- A tiny gap occurs between the change in opacity, and the change in width.
- Nothing animates during the last 25% of the timeline.
- Increasing the padding makes the widget appear to rise upward.
- Increasing the border radius to 0.5, transforms the square with rounded corners into a circle.
- The padding and border radius changes occur during the same exact interval, but they don’t have to.
To set up the animation:
- Create an AnimationController that manages all of the Animations.
- Create a Tween for each property being animated.
- The Tween defines a range of values.
- The Tween’s
animate
method requires theparent
controller, and produces an Animation for that property.
- Specify the interval on the Animation’s
curve
property.
When the controlling animation’s value changes, the new animation’s value changes, triggering the UI to update.
The following code creates a tween for the width
property. It builds a CurvedAnimation, specifying an eased curve. See Curves for other available pre-defined animation curves.
width = Tween<double>( begin: 50.0, end: 150.0, ).animate( CurvedAnimation( parent: controller, curve: Interval( 0.125, 0.250, curve: Curves.ease, ), ), ),
The begin
and end
values don’t have to be doubles. The following code builds the tween for the borderRadius
property (which controls the roundness of the square’s corners), using BorderRadius.circular()
.
borderRadius = BorderRadiusTween( begin: BorderRadius.circular(4.0), end: BorderRadius.circular(75.0), ).animate( CurvedAnimation( parent: controller, curve: Interval( 0.375, 0.500, curve: Curves.ease, ), ), ),
Complete staggered animation
Like all interactive widgets, the complete animation consists of a widget pair: a stateless and a stateful widget.
The stateless widget specifies the Tweens, defines the Animation objects, and provides a build()
function responsible for building the animating portion of the widget tree.
The stateful widget creates the controller, plays the animation, and builds the non-animating portion of the widget tree. The animation begins when a tap is detected anywhere in the screen.
Full code for basic_staggered_animation’s main.dart
Stateless widget: StaggerAnimation
In the stateless widget, StaggerAnimation, the build()
function instantiates an AnimatedBuilder—a general purpose widget for building animations. The AnimatedBuilder builds a widget and configures it using the Tweens’ current values. The example creates a function named _buildAnimation()
(which performs the actual UI updates), and assigns it to its builder
property. AnimatedBuilder listens to notifications from the animation controller, marking the widget tree dirty as values change. For each tick of the animation, the values are updated, resulting in a call to _buildAnimation()
.
class StaggerAnimation extends StatelessWidget { StaggerAnimation({ Key key, this.controller }) : // Each animation defined here transforms its value during the subset // of the controller's duration defined by the animation's interval. // For example the opacity animation transforms its value during // the first 10% of the controller's duration. opacity = Tween<double>( begin: 0.0, end: 1.0, ).animate( CurvedAnimation( parent: controller, curve: Interval( 0.0, 0.100, curve: Curves.ease, ), ), ), // ... Other tween definitions ... super(key: key); final Animation<double> controller; final Animation<double> opacity; final Animation<double> width; final Animation<double> height; final Animation<EdgeInsets> padding; final Animation<BorderRadius> borderRadius; final Animation<Color> color; // This function is called each time the controller "ticks" a new frame. // When it runs, all of the animation's values will have been // updated to reflect the controller's current value. Widget _buildAnimation(BuildContext context, Widget child) { return Container( padding: padding.value, alignment: Alignment.bottomCenter, child: Opacity( opacity: opacity.value, child: Container( width: width.value, height: height.value, decoration: BoxDecoration( color: color.value, border: Border.all( color: Colors.indigo[300], width: 3.0, ), borderRadius: borderRadius.value, ), ), ), ); } @override Widget build(BuildContext context) { return AnimatedBuilder( builder: _buildAnimation, animation: controller, ); } }
Stateful widget: StaggerDemo
The stateful widget, StaggerDemo, creates the AnimationController (the one who rules them all), specifying a 2000 ms duration. It plays the animation, and builds the non-animating portion of the widget tree. The animation begins when a tap is detected in the screen. The animation runs forward, then backward.
class StaggerDemo extends StatefulWidget { @override _StaggerDemoState createState() => _StaggerDemoState(); } class _StaggerDemoState extends State<StaggerDemo> with TickerProviderStateMixin { AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this ); } // ...Boilerplate... Future<void> _playAnimation() async { try { await _controller.forward().orCancel; await _controller.reverse().orCancel; } on TickerCanceled { // the animation got canceled, probably because we were disposed } } @override Widget build(BuildContext context) { timeDilation = 10.0; // 1.0 is normal animation speed. return Scaffold( appBar: AppBar( title: const Text('Staggered Animation'), ), body: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { _playAnimation(); }, child: Center( child: Container( width: 300.0, height: 300.0, decoration: BoxDecoration( color: Colors.black.withOpacity(0.1), border: Border.all( color: Colors.black.withOpacity(0.5), ), ), child: StaggerAnimation( controller: _controller.view ), ), ), ), ); } }
Resources
The following resources might help when writing animations:
- Animations landing page
- Lists the available documentation for Flutter animations. If tweens are new to you, check out the Animations tutorial.
- Flutter API documentation
- Reference documentation for all of the Flutter libraries. In particular, see the animation library documentation.
- Flutter Gallery
- Demo app showcasing many Material Components and other Flutter features. The Shrine demo implements a hero animation.
- Material motion spec
- Describes motion for Material apps.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论