mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
add animations basics 1-6 (#120)
* add basics * web: update dependencies * TransferableTypeData added (#116) * Updating index with new samples (#121) * use arrow functions * remove newline * use verbs: random*() -> generate*() * remove <Widget>[] type annotation on lists * use raised button * _route() => _createRoute() * add parameter names to pageBuilder * use the text theme's display1 for large text * dispose animation controllers before calling super() * remove local var * use raised buttons instead of material buttons * web: updated dependencies * Added new test scripts (#122) * add carousel, card_swipe, and focus_image samples (#119) * add carousel, card_swipe, and focus_image samples * fix image assets * fix more asset images * add repeating animation * fix import * add copyright headers * remove Center widget * imageAssetName * use ClipRect, refactor _SwipeableCardState * use offset.zero * add comments * remove reference to coverflow package * change spread to toList() * refactor coverflow sample don't set width and height use const data -> images * return widget directly, fix formatting * inline transitionsBuilder * image -> imageAssetName * _rectTween() => _createTween() * _expandToPageRoute -> _createRoute * move non-updating widgets out of AnimatedBuilder * code review updates to animations demos
This commit is contained in:
@@ -4,7 +4,12 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'src/basics/animation_controller_demo.dart';
|
import 'src/basics/01_animated_container.dart';
|
||||||
|
import 'src/basics/02_page_route_builder.dart';
|
||||||
|
import 'src/basics/03_animation_controller.dart';
|
||||||
|
import 'src/basics/04_tweens.dart';
|
||||||
|
import 'src/basics/05_custom_tween.dart';
|
||||||
|
import 'src/basics/06_animated_builder.dart';
|
||||||
import 'src/misc/card_swipe.dart';
|
import 'src/misc/card_swipe.dart';
|
||||||
import 'src/misc/carousel.dart';
|
import 'src/misc/carousel.dart';
|
||||||
import 'src/misc/expand_card.dart';
|
import 'src/misc/expand_card.dart';
|
||||||
@@ -22,8 +27,17 @@ class Demo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final basicDemos = [
|
final basicDemos = [
|
||||||
|
Demo('AnimatedContainer', AnimatedContainerDemo.routeName,
|
||||||
|
(context) => AnimatedContainerDemo()),
|
||||||
|
Demo('PageRouteBuilder', PageRouteBuilderDemo.routeName,
|
||||||
|
(context) => PageRouteBuilderDemo()),
|
||||||
Demo('Animation Controller', AnimationControllerDemo.routeName,
|
Demo('Animation Controller', AnimationControllerDemo.routeName,
|
||||||
(context) => AnimationControllerDemo()),
|
(context) => AnimationControllerDemo()),
|
||||||
|
Demo('Tweens', TweenDemo.routeName, (context) => TweenDemo()),
|
||||||
|
Demo('Custom Tween', CustomTweenDemo.routeName,
|
||||||
|
(context) => CustomTweenDemo()),
|
||||||
|
Demo('AnimatedBuilder', AnimatedBuilderDemo.routeName,
|
||||||
|
(context) => AnimatedBuilderDemo()),
|
||||||
];
|
];
|
||||||
|
|
||||||
final miscDemos = [
|
final miscDemos = [
|
||||||
|
|||||||
69
animations/lib/src/basics/01_animated_container.dart
Normal file
69
animations/lib/src/basics/01_animated_container.dart
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const _duration = Duration(milliseconds: 400);
|
||||||
|
|
||||||
|
double generateBorderRadius() => Random().nextDouble() * 64;
|
||||||
|
double generateMargin() => Random().nextDouble() * 64;
|
||||||
|
Color generateColor() => Color(0xFFFFFFFF & Random().nextInt(0xFFFFFFFF));
|
||||||
|
|
||||||
|
class AnimatedContainerDemo extends StatefulWidget {
|
||||||
|
static String routeName = '/basics/01_animated_container';
|
||||||
|
|
||||||
|
_AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {
|
||||||
|
Color color;
|
||||||
|
double borderRadius;
|
||||||
|
double margin;
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
color = Colors.deepPurple;
|
||||||
|
borderRadius = generateBorderRadius();
|
||||||
|
margin = generateMargin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void change() {
|
||||||
|
setState(() {
|
||||||
|
color = generateColor();
|
||||||
|
borderRadius = generateBorderRadius();
|
||||||
|
margin = generateMargin();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
margin: EdgeInsets.all(margin),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
borderRadius: BorderRadius.circular(borderRadius),
|
||||||
|
),
|
||||||
|
duration: _duration,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RaisedButton(
|
||||||
|
child: Text(
|
||||||
|
'change',
|
||||||
|
),
|
||||||
|
onPressed: () => change(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
animations/lib/src/basics/02_page_route_builder.dart
Normal file
46
animations/lib/src/basics/02_page_route_builder.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PageRouteBuilderDemo extends StatelessWidget {
|
||||||
|
static const String routeName = '/basics/page_route_builder';
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Center(
|
||||||
|
child: RaisedButton(
|
||||||
|
child: Text('Go!'),
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(_createRoute());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Route _createRoute() {
|
||||||
|
return PageRouteBuilder(
|
||||||
|
pageBuilder: (context, animation, secondaryAnimation) => _Page2(),
|
||||||
|
transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
||||||
|
var tween = Tween<Offset>(begin: Offset(0.0, 1.0), end: Offset.zero);
|
||||||
|
var curveTween = CurveTween(curve: Curves.ease);
|
||||||
|
|
||||||
|
return SlideTransition(
|
||||||
|
position: animation.drive(curveTween).drive(tween),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Page2 extends StatelessWidget {
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Center(
|
||||||
|
child: Text('Page 2!', style: Theme.of(context).textTheme.display1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,8 +30,8 @@ class _AnimationControllerDemoState extends State<AnimationControllerDemo>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
63
animations/lib/src/basics/04_tweens.dart
Normal file
63
animations/lib/src/basics/04_tweens.dart
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TweenDemo extends StatefulWidget {
|
||||||
|
static const String routeName = '/basics/tweens';
|
||||||
|
|
||||||
|
_TweenDemoState createState() => _TweenDemoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TweenDemoState extends State<TweenDemo>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
static const Duration _duration = Duration(seconds: 1);
|
||||||
|
static const double accountBalance = 1000000;
|
||||||
|
AnimationController controller;
|
||||||
|
Animation<double> animation;
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
controller = AnimationController(vsync: this, duration: _duration)
|
||||||
|
..addListener(() {
|
||||||
|
// Marks the widget tree as dirty
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
animation = Tween(begin: 0.0, end: accountBalance).animate(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: 200),
|
||||||
|
child: Text('\$${animation.value.toStringAsFixed(2)}',
|
||||||
|
style: TextStyle(fontSize: 24)),
|
||||||
|
),
|
||||||
|
RaisedButton(
|
||||||
|
child: Text(
|
||||||
|
controller.status == AnimationStatus.completed
|
||||||
|
? 'Buy a Mansion'
|
||||||
|
: 'Win Lottery',
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.status == AnimationStatus.completed) {
|
||||||
|
controller.reverse();
|
||||||
|
} else {
|
||||||
|
controller.forward();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
98
animations/lib/src/basics/05_custom_tween.dart
Normal file
98
animations/lib/src/basics/05_custom_tween.dart
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TypewriterTween extends Tween<String> {
|
||||||
|
TypewriterTween({String begin = '', String end})
|
||||||
|
: super(begin: begin, end: end);
|
||||||
|
|
||||||
|
String lerp(double t) {
|
||||||
|
var cutoff = (end.length * t).round();
|
||||||
|
return end.substring(0, cutoff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomTweenDemo extends StatefulWidget {
|
||||||
|
static const String routeName = '/basics/custom_tweens';
|
||||||
|
|
||||||
|
_CustomTweenDemoState createState() => _CustomTweenDemoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomTweenDemoState extends State<CustomTweenDemo>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
static const Duration _duration = Duration(seconds: 3);
|
||||||
|
static const String message = loremIpsum;
|
||||||
|
AnimationController controller;
|
||||||
|
Animation<String> animation;
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
controller = AnimationController(vsync: this, duration: _duration)
|
||||||
|
..addListener(() {
|
||||||
|
// Marks the widget tree as dirty
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
animation = TypewriterTween(end: message).animate(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
actions: [
|
||||||
|
RaisedButton(
|
||||||
|
child: Text(
|
||||||
|
controller.status == AnimationStatus.completed
|
||||||
|
? 'Delete Essay'
|
||||||
|
: 'Write Essay',
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.status == AnimationStatus.completed) {
|
||||||
|
controller.reverse();
|
||||||
|
} else {
|
||||||
|
controller.forward();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Card(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text('${animation.value}',
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 16, fontFamily: 'SpecialElite')),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const String loremIpsum = '''
|
||||||
|
Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium
|
||||||
|
doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore
|
||||||
|
veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim
|
||||||
|
ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia
|
||||||
|
consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque
|
||||||
|
porro quisquam est, qui dolorem ipsum, quia dolor sit amet consectetur
|
||||||
|
adipisci[ng] velit, sed quia non-numquam [do] eius modi tempora inci[di]dunt, ut
|
||||||
|
labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
|
||||||
|
quis nostrum[d] exercitationem ullam corporis suscipit laboriosam, nisi ut
|
||||||
|
aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in
|
||||||
|
ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui
|
||||||
|
dolorem eum fugiat, quo voluptas nulla pariatur?
|
||||||
|
''';
|
||||||
57
animations/lib/src/basics/06_animated_builder.dart
Normal file
57
animations/lib/src/basics/06_animated_builder.dart
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AnimatedBuilderDemo extends StatefulWidget {
|
||||||
|
static const String routeName = '/basics/animated_builder';
|
||||||
|
|
||||||
|
_AnimatedBuilderDemoState createState() => _AnimatedBuilderDemoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AnimatedBuilderDemoState extends State<AnimatedBuilderDemo>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
static const Color beginColor = Colors.deepPurple;
|
||||||
|
static const Color endColor = Colors.deepOrange;
|
||||||
|
Duration duration = Duration(milliseconds: 800);
|
||||||
|
AnimationController controller;
|
||||||
|
Animation<Color> animation;
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
controller = AnimationController(vsync: this, duration: duration);
|
||||||
|
animation =
|
||||||
|
ColorTween(begin: beginColor, end: endColor).animate(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Center(
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: this.animation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return MaterialButton(
|
||||||
|
color: animation.value,
|
||||||
|
child: child,
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.status == AnimationStatus.completed) {
|
||||||
|
controller.reverse();
|
||||||
|
} else {
|
||||||
|
controller.forward();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Change Color',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ class _ExpandCardState extends State<ExpandCard>
|
|||||||
layoutBuilder:
|
layoutBuilder:
|
||||||
(topChild, topChildKey, bottomChild, bottomChildKey) {
|
(topChild, topChildKey, bottomChild, bottomChildKey) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: <Widget>[
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
key: bottomChildKey,
|
key: bottomChildKey,
|
||||||
child: bottomChild,
|
child: bottomChild,
|
||||||
|
|||||||
Reference in New Issue
Block a user