diff --git a/animations/README.md b/animations/README.md index 6bf214234..190c5412c 100644 --- a/animations/README.md +++ b/animations/README.md @@ -12,7 +12,7 @@ Sample apps that showcasing Flutter's animation features Building blocks and patterns -1. **AnimatedContainerDemo** Demonstrates how to use `AnimatedContainer` +1. **AnimatedContainerDemo** Demonstrates how to use `AnimatedContainer`. 2. **PageRouteBuilderDemo** Demonstrates how to use `Tween` and `Animation` to *build a custom page route transition. 3. **AnimationControllerDemo** Demonstrates how to use an `AnimationController`. @@ -23,7 +23,9 @@ Building blocks and patterns 6. **CustomTweenDemo** Demonstrates how to extend `Tween`. 7. **TweenSequenceDemo** Demonstrates how to use `TweenSequence` to build a button that changes between different colors. -8. **FadeTransitionDemo** Demonstrates how to use `FadeTransition`. +8. **FadeTransitionDemo** Demonstrates how to use `FadeTransition`. +9. **AnimatedPositionedDemo** Demonstrates how to use `AnimatedPositioned`. +10. **AnimatedSwitcherDemo** Demonstrates how to use `AnimatedSwitcher`. ### Misc @@ -39,8 +41,9 @@ it using a `PageRouteBuilder`. spring simulation. - **CardSwipeDemo** A swipeable card that demonstrates how to use gesture detection to drive an animation. -- **AnimatedList** Demonstrates how to use `AnimatedList` +- **AnimatedList** Demonstrates how to use `AnimatedList`. - **HeroAnimationDemo** Demonstrates how to use `Hero` animation. +- **CurvedAnimationDemo** Demonstrates how to use different curves in `CurvedAnimation`. ## Other Resources diff --git a/animations/lib/main.dart b/animations/lib/main.dart index 7f76fb066..924d624d6 100644 --- a/animations/lib/main.dart +++ b/animations/lib/main.dart @@ -16,6 +16,7 @@ import 'src/basics/10_animated_switcher.dart'; import 'src/misc/animated_list.dart'; import 'src/misc/card_swipe.dart'; import 'src/misc/carousel.dart'; +import 'src/misc/curved_animation.dart'; import 'src/misc/expand_card.dart'; import 'src/misc/focus_image.dart'; import 'src/misc/hero_animation.dart'; @@ -108,6 +109,10 @@ final miscDemos = [ name: 'Hero Animation', route: HeroAnimationDemo.routeName, builder: (context) => HeroAnimationDemo()), + Demo( + name: 'Curved Animation', + route: CurvedAnimationDemo.routeName, + builder: (context) => CurvedAnimationDemo()), ]; final basicDemoRoutes = diff --git a/animations/lib/src/misc/curved_animation.dart b/animations/lib/src/misc/curved_animation.dart new file mode 100644 index 000000000..c7bf12e80 --- /dev/null +++ b/animations/lib/src/misc/curved_animation.dart @@ -0,0 +1,165 @@ +// Copyright 2020 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; +import 'package:flutter/material.dart'; + +class CurvedAnimationDemo extends StatefulWidget { + static const String routeName = '/misc/curved_animation'; + + @override + _CurvedAnimationDemoState createState() => _CurvedAnimationDemoState(); +} + +class CurveChoice { + final Curve curve; + final String name; + const CurveChoice({this.curve, this.name}); +} + +class _CurvedAnimationDemoState extends State + with SingleTickerProviderStateMixin { + AnimationController controller; + Animation animationRotation; + Animation animationTranslation; + static const _duration = Duration(seconds: 4); + List curves = [ + CurveChoice(curve: Curves.bounceIn, name: 'Bounce In'), + CurveChoice(curve: Curves.bounceOut, name: 'Bounce Out'), + CurveChoice(curve: Curves.easeInCubic, name: 'Ease In Cubic'), + CurveChoice(curve: Curves.easeOutCubic, name: 'Ease Out Cubic'), + CurveChoice(curve: Curves.easeInExpo, name: 'Ease In Expo'), + CurveChoice(curve: Curves.easeOutExpo, name: 'Ease Out Expo'), + CurveChoice(curve: Curves.elasticIn, name: 'Elastic In'), + CurveChoice(curve: Curves.elasticOut, name: 'Elastic Out'), + CurveChoice(curve: Curves.easeInQuart, name: 'Ease In Quart'), + CurveChoice(curve: Curves.easeOutQuart, name: 'Ease Out Quart'), + CurveChoice(curve: Curves.easeInCirc, name: 'Ease In Circle'), + CurveChoice(curve: Curves.easeOutCirc, name: 'Ease Out Circle'), + ]; + CurveChoice selectedForwardCurve, selectedReverseCurve; + CurvedAnimation curvedAnimation; + + @override + void initState() { + super.initState(); + controller = AnimationController( + duration: _duration, + vsync: this, + ); + selectedForwardCurve = curves[0]; + selectedReverseCurve = curves[0]; + curvedAnimation = CurvedAnimation( + parent: controller, + curve: selectedForwardCurve.curve, + reverseCurve: selectedReverseCurve.curve, + ); + animationRotation = Tween( + begin: 0, + end: 2 * math.pi, + ).animate(curvedAnimation) + ..addListener(() { + setState(() {}); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + controller.reverse(); + } + }); + animationTranslation = Tween( + begin: Offset(-1, 0), + end: Offset(1, 0), + ).animate(curvedAnimation) + ..addListener(() { + setState(() {}); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + controller.reverse(); + } + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Curved Animation'), + ), + body: Column( + children: [ + SizedBox(height: 20.0), + Text( + 'Select Curve for forward motion', + style: Theme.of(context).textTheme.title, + ), + DropdownButton( + items: curves.map((curve) { + return DropdownMenuItem( + value: curve, child: Text(curve.name)); + }).toList(), + onChanged: (newCurve) { + setState(() { + selectedForwardCurve = newCurve; + curvedAnimation.curve = selectedForwardCurve.curve; + }); + }, + value: selectedForwardCurve, + ), + SizedBox(height: 15.0), + Text( + 'Select Curve for reverse motion', + style: Theme.of(context).textTheme.title, + ), + DropdownButton( + items: curves.map((curve) { + return DropdownMenuItem( + value: curve, child: Text(curve.name)); + }).toList(), + onChanged: (newCurve) { + setState(() { + selectedReverseCurve = newCurve; + curvedAnimation.reverseCurve = selectedReverseCurve.curve; + }); + }, + value: selectedReverseCurve, + ), + SizedBox(height: 35.0), + Transform.rotate( + angle: animationRotation.value, + child: Center( + child: Container( + child: FlutterLogo( + size: 100, + ), + ), + ), + ), + SizedBox(height: 35.0), + FractionalTranslation( + translation: animationTranslation.value, + child: Container( + child: FlutterLogo( + size: 100, + ), + ), + ), + SizedBox(height: 25.0), + RaisedButton( + onPressed: () { + controller.forward(); + }, + child: Text('Animate'), + ), + ], + ), + ); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } +}