Flutter Animations First Step

35e08efcf39d692f540047fb756eb4e3?s=47 konifar
September 01, 2018

Flutter Animations First Step

GDG Tokyo 2018で話した、Flutterでアニメーションを実装する方法です。
https://gdg-tokyo.connpass.com/event/95307/

35e08efcf39d692f540047fb756eb4e3?s=128

konifar

September 01, 2018
Tweet

Transcript

  1. Flutter Animations First Step 2018/09/01 (౔) DevFest @konifar

  2. None
  3. Kyash Inc.

  4. yome.fm

  5. My First Flutter app

  6. Kyash͸౤͛મ΋Ͱ͖Δ ؆୯ʹܾࡁɾૹۚͰ͖Δ΢ΥϨοτΞϓϦɻ “39ԁ”ૹΔͱͪΐͬͱͨ͠Կ͔͕ى͜Δɻ https://goo.gl/C594Ri kyash_id : konifar

  7. Flutter Animations

  8. Useful Links - FlutterΞχϝʔγϣϯͷΫϥε΍֓೦ɺαϯϓϧͷઆ໌
 https://flutter.io/tutorials/animation/
 https://flutter.io/animations/ - গ͠ෳࡶͳάϥϑΞχϝʔγϣϯΛ࡞ΔνϡʔτϦΞϧ
 https://medium.com/flutter-io/zero-to-one-with-flutter-43b13fd7b354
 https://medium.com/flutter-io/zero-to-one-with-flutter-part-two-

    5aa2f06655cb - ίʔυϥϘͰͷ؆୯ͳΞχϝʔγϣϯ࣮૷
 https://codelabs.developers.google.com/codelabs/flutter/index.html#6
  9. Goal FlutterͷΞχϝʔγϣϯΛΩϟονΞοϓ͢ Δ࣌ʹɺυΩϡϝϯτ΍νϡʔτϦΞϧ͕ཧղ ͠΍͍͢Α͏ʹ֓೦Λβοͱཧղ͢Δɻ

  10. ࿩͢͜ͱ - ΞχϝʔγϣϯΛ࣮૷͢ΔجຊͷྲྀΕ - ࣮૷͢Δ࣌ͷΫϥεͷ໾ׂ

  11. ࿩͞ͳ͍͜ͱ - Ξχϝʔγϣϯ಺෦ͷ࣮૷ͷ࿩ - ෳࡶͳΞχϝʔγϣϯͷ࿩ - Gestureͱ૊Έ߹Θͤͨ৔߹ͷ࿩

  12. ԡ͓͑ͯ͘͞΂͖ Ϋϥε

  13. Basic classes 1. AnimationController 2. Tween 3. CurvedAnimation 4. AnimatedBuilder

  14. ͜ΕΒͷઆ໌Λ͢Δલʹ

  15. ͦ΋ͦ΋Animationͱ͸ ʰҰఆ࣌ؒͰɺϏϡʔͷϓϩύςΟͷ஋ΛมԽ ͤ͞ɺඳը͢ΔҰ࿈ͷྲྀΕʱ
 ͬ͘͟Γݴ͏ͱɺύϥύϥ·Μ͕

  16. ྫ͑͹ 2ඵؒʢҰఆ࣌ؒʣͰɺ width, heightʢϓϩύ ςΟʣͷ஋ΛมԽͤ͞ɺ ϑϨʔϜ͕ߋ৽͞ΕΔ͝ͱ ʹඳը͢Δɻ

  17. ଞʹ΋ - colorΛม͑Ε͹৭͕มΘΔ - opacityΛม͑Ε͹ಁա౓͕มΘΔ - x,y࠲ඪΛม͑Ε͹Ҡಈ͢Δ - radiusΛม͑Ε͹˘͔Β˓ʹมΘΔ

  18. Basic classes - AnimationController - ࣌ؒΛܾΊɺ։࢝ɾऴྃͳͲͷ੍ޚΛ͢Δ - Tween - มߋ͢Δ஋ͷൣғΛܾΊΔ

    - CurvedAnimation - ஋ͷมԽʹ؇ٸΛ͚ͭΔ - AnimatedBuilder - มԽͨ͠஋Λඳը͢Δ
  19. Basic classes - AnimationController - 2000ms ͷ࣌ؒͰϦϐʔτ - Tween -

    0~300 ͷ஋ - CurvedAnimation - Linearʢ౳଎ʣ - AnimatedBuilder - 1ඵؒʹ60ճ˘Λඳը
  20. Basic classes - AnimationController - 2000ms ͷ࣌ؒͰϦϐʔτ - Tween -

    0~300 ͷ஋ - CurvedAnimation - Linearʢ౳଎ʣ - AnimatedBuilder - 1ඵؒʹ60ճ˘Λඳը Required Optional
  21. ؆୯ͳΞχϝʔγϣϯΛ ͜ΕΒͷΫϥεΛͻͱͭͣͭ ࢖͍ͳ͕Βҭ͍͖ͯͯ·͢

  22. 1. AnimationController͚ͩͰ࡞ͬͯΈΔ 2. TweenΛ͔ͭ͏ 3. CurvedAnimationͰ؇ٸΛ͚ͭΔ 4. Animation෦෼ΛWidgetʹ੾Γग़͢ 5. AnimatedBuilderͰϦϑΝΫλϦϯά

    6. ࿈ଓͨ͠ΞχϝʔγϣϯΛ࡞Δ
  23. None
  24. AnimationController ͚ͩͰ࡞ͬͯΈΔ

  25. AnimationController - ΞχϝʔγϣϯΛ੍ޚ͢ΔඞਢΫϥε - AnimationΫϥεΛܧঝ - ϑϨʔϜ͝ͱʹ0.0 ~ 1.0ͷؒͷ஋Λੜ੒ -

    ը໘্Ͳ͏දࣔ͞ΕΔ͔͸஌Βͳ͍
  26. ͜ΕΛ࡞Δ ੨͍˘͕2ඵ͔͚ͯ 300.0ͷେ͖͞·Ͱ ֦େ͞ΕΔΞχϝʔγϣϯ

  27. class BasicAnimationApp extends StatefulWidget { @override _BasicAnimationAppState createState() => new

    _BasicAnimationAppState(); } class _BasicAnimationAppState extends State<BasicAnimationApp> { @override Widget build(BuildContext context) { return Center( child: Container( width: 300.0, height: 300.0, decoration: BoxDecoration( color: Colors.blue[400], ), ), ); } } void main() { runApp(BasicAnimationApp()); } Ξχϝʔγϣϯͳ͠
  28. class BasicAnimationApp extends StatefulWidget { @override _BasicAnimationAppState createState() => new

    _BasicAnimationAppState(); } class _BasicAnimationAppState extends State<BasicAnimationApp> { @override Widget build(BuildContext context) { return Center( child: Container( width: 300.0, height: 300.0, decoration: BoxDecoration( color: Colors.blue[400], ), ), ); } } void main() { runApp(BasicAnimationApp()); } Ξχϝʔγϣϯͳ͠ buildϝιουͷதͷ width, height ͕ 300ݻఆͳͷͰɺͨͩͷ੨͍˘͕දࣔ͞ΕΔ͚ͩɻ
  29. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } …
  30. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … initState()ͷதͰɺ2000msͰಈ࡞͢Δ AnimationControllerΠϯελϯεΛੜ੒ɻ
  31. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … Ξχϝʔγϣϯ࣌ͷແବͳඳըΛ๷͙ͨΊʹ ର৅ͷStateʹTickerProviderΛ࣮૷ͯ͠౉͢ɻ
  32. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … initState()ͷதͰΞχϝʔγϣϯͷ։࢝ɻ දࣔͨ͠Β͙͢ʹಈ͖ग़͢ɻ
  33. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … buildϝιουͷதͰɺcontroller.valueͷ஋Λ ࢖ͬͯWidgetπϦʔΛ࡞Δɻ controller.value͸0.0~1.0ͳͷͰɺ 300ഒͯ͠widthͱheightʹηοτ͢Δɻ
  34. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … AnimationController͕஋Λੜ੒ ͢Δͨͼʹඳը͢ΔͨΊʹɺ ListenerΛηοτͯ͠setState() ΛݺͿɻ
  35. None
  36. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; ..

    @override dispose() { controller.dispose(); super.dispose(); } } dispose() Λ๨Εͣʹ dispose() ΛݺΜͰ͓͔ͳ͍ͱ ϝϞϦϦʔΫ͢ΔͷͰ஫ҙɻ
  37. addStatusListener() - Ξχϝʔγϣϯͷεςʔλε͕มΘͬͨ࣌ʹ ݺ͹ΕΔListener - forwardʢਖ਼ํ޲ʹಈ͍͍ͯΔʣ - reverseʢ൓ରํ޲ʹಈ͍͍ͯΔʣ - completedʢforwardͰऴྃͨ͠ʣ

    - dismissedʢreverseͰऴྃͨ͠ʣ
  38. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; @override

    initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) ..addListener(() { setState(() { }); }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); controller.forward(); } Ξχϝʔγϣϯ͕ऴΘͬͨΒ൓ରํ޲ʢreverseʣʹ ಈ͔ͯ͠ɺऴΘͬͨΒ·ͨ։࢝ʢforwardʣ͢Δɻ
  39. None
  40. timeDilationͰ଎౓Λมߋ - timeDilation = 2.0 Λ௥Ճ͢Δͱ
 1/2ͷ଎͞ͰΞχϝʔγϣϯ͢Δ - σόοάͰΞχϝʔγϣϯͷ଎౓Λมߋ͢Δ ͷʹศར

  41. import 'package:flutter/scheduler.dart';
 
 class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin {

    AnimationController controller; .. @override Widget build(BuildContext context) {
 timeDilation = 2.0; return Center( child: Container( width: controller.value * 300.0, height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } .. scheduler.dartΛimport͠ timeDilationʹ஋Ληοτ͢Δɻ
  42. TweenΛ͔ͭ͏

  43. Tween - ΞχϝʔγϣϯͰੜ੒͢Δ஋ʢ0.0 ~ 1.0ʣ Λଞͷ஋ʹม׵͢Δ - ઌ΄Ͳͷྫͩͱɺ0.0 ~ 300.0

  44. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), // width: controller.value * 300.0, // height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } …
  45. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), // width: controller.value * 300.0, // height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … 0.0 ~ 300.0 Ͱ஋ΛมԽͤ͞ΔͨΊͷ doubleܕͷTweenΠϯελϯεΛੜ੒ɻ
  46. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), // width: controller.value * 300.0, // height: controller.value * 300.0, decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … buildϝιουͰWidgetΛ૊ΈཱͯΔࡍʹ Tween͔Β0.0 ~ 300.0ͷ஋Λड͚औΕΔɻ
  47. ͞·͟·ͳ Tween - ColorTween - SizeTween - RectTween - BorderRadiusTween

    - DecorationTween - BoxConstraintsTween - https://docs.flutter.io/flutter/animation/Tween-class.html
  48. ColorTween ੨͔ΒԫʹมԽ͢Δ ΞχϝʔγϣϯΛ௥Ճɻ

  49. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); final _colorTween = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), decoration: BoxDecoration(color: Colors.blue[400]), // decoration: BoxDecoration(color: Colors.blue[400]), ), ); } …
  50. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); final _colorTween = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), decoration: BoxDecoration(color: Colors.blue[400]), // decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … beginʹ੨ɺendʹԫ৭Λ౉ͯ͠ ColorTween ΠϯελϯεΛੜ੒ɻ
  51. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller;
 final

    _sizeTween = Tween<double>(begin: 0.0, end: 300.0); final _colorTween = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); @override initState() { super.initState(); controller = AnimationController( .. controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(controller), height: _sizeTween.evaluate(controller), decoration: BoxDecoration(color: _colorTween.evaluate(controller)), // decoration: BoxDecoration(color: Colors.blue[400]), ), ); } … buildϝιουͷதͰɺ ColorTween ͔Β Color ΛऔΓग़ͯ͠ηοτɻ
  52. None
  53. CurvedAnimation Ͱ؇ٸΛ͚ͭΔ

  54. CurvedAnimation - Ξχϝʔγϣϯͷ஋ͷมԽʹ؇ٸΛ͚ͭΔ

  55. Curves.ease

  56. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation

    animation; .. @override initState() { super.initState(); controller = AnimationController( .. animation = CurvedAnimation(parent: controller, curve: Curves.ease); controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(animation), height: _sizeTween.evaluate(animation), decoration: BoxDecoration(color: _colorTween.evaluate(animation)), ), ); } ..
  57. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation

    animation; .. @override initState() { super.initState(); controller = AnimationController( .. animation = CurvedAnimation(parent: controller, curve: Curves.ease); controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(animation), height: _sizeTween.evaluate(animation), decoration: BoxDecoration(color: _colorTween.evaluate(animation)), ), ); } .. initState()ͷதͰɺCurvedAnimationΛੜ੒ɻ ୈೋҾ਺ͰCurveΛࢦఆ͢Δɻ
  58. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation

    animation; .. @override initState() { super.initState(); controller = AnimationController( .. animation = CurvedAnimation(parent: controller, curve: Curves.ease); controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(animation), height: _sizeTween.evaluate(animation), decoration: BoxDecoration(color: _colorTween.evaluate(animation)), ), ); } .. buildϝιουͷதͰTween͔Β஋ΛऔΓग़͢ࡍʹ controllerͷ୅ΘΓʹanimationΛࢦఆ͢Δɻ
  59. None
  60. Curves - bounceIn/bounceInOut/bounceOut - Decelerate - ease/easeIn/easeInOut/easeOut - elasticIn/elasticInOut/elasticOut -

    FastOutSlowIn - Linear - https://docs.flutter.io/flutter/animation/Curves-class.html
  61. Animation෦෼Λ Widgetʹ੾Γग़͢

  62. ͜͜·Ͱͷ໰୊఺ - Animationͷίʔυ͕ࢄΒ͹͍ͬͯΔ - Animation͢ΔWidget͕૿͑ͨΓෳࡶʹ ͳͬͨͱ͖ʹେม

  63. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation

    animation; final _sizeTween = Tween<double>(begin: 0.0, end: 300.0); final _colorTween = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); .. @override initState() { super.initState(); controller = AnimationController( .. animation = CurvedAnimation(parent: controller, curve: Curves.ease); controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(animation), height: _sizeTween.evaluate(animation), decoration: BoxDecoration(color: _colorTween.evaluate(animation)), ), ); } ..
  64. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation

    animation; final _sizeTween = Tween<double>(begin: 0.0, end: 300.0); final _colorTween = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); .. @override initState() { super.initState(); controller = AnimationController( .. animation = CurvedAnimation(parent: controller, curve: Curves.ease); controller.forward(); } @override Widget build(BuildContext context) { return Center( child: Container( width: _sizeTween.evaluate(animation), height: _sizeTween.evaluate(animation), decoration: BoxDecoration(color: _colorTween.evaluate(animation)), ), ); } .. ͜ͷ͋ͨΓΛ1ͭͷWidgetʹ·ͱΊΕ͹ ݟ௨͠΋Α͘ͳΔ͠࠶ར༻΋ՄೳʹͳΔɻ
  65. Animation͢Δ෦෼Λ Widgetͱͯ͠੾Γग़͠

  66. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), super(key: key); final Animation<double> controller; final Animation<double> sizeAnimation; final Animation<Color> colorAnimation; @override Widget build(BuildContext context) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } }
  67. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), super(key: key); final Animation<double> controller; final Animation<double> sizeAnimation; final Animation<Color> colorAnimation; @override Widget build(BuildContext context) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } } Ҿ਺ʹAnimationControllerΛ࣋ͭ StatelessWidgetɻ
  68. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), super(key: key); final Animation<double> controller; final Animation<double> sizeAnimation; final Animation<Color> colorAnimation; @override Widget build(BuildContext context) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } } TweenͱCurvedAnimationΛ࢖ͬͯ sizeAnimationͱcolorAnimationΛ ίϯετϥΫλͰੜ੒͓ͯ͘͠ɻ
  69. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]).animate( CurvedAnimation(parent: controller, curve: Curves.ease), ), super(key: key); final Animation<double> controller; final Animation<double> sizeAnimation; final Animation<Color> colorAnimation; @override Widget build(BuildContext context) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } } buildϝιουͷதͰ sizeAnimationͱColorAnimationͷ ஋Λ࢖ͬͯWidgetπϦʔΛߏஙɻ
  70. AnimationController controller; // Animation animation; // final _sizeTween = Tween<double>(begin:

    0.0, end: 300.0); // final _colorTween = // ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]); @override initState() { super.initState(); controller = AnimationController( .. // animation = CurvedAnimation(parent: controller, curve: Curves.ease); // _sizeTween.animate(animation); // _colorTween.animate(animation); controller.forward(); } @override Widget build(BuildContext context) { // timeDilation = 2.0; // return Center( // child: Container( // width: _sizeTween.evaluate(animation), // height: _sizeTween.evaluate(animation), // decoration: BoxDecoration(color: _colorTween.evaluate(animation)), // ), // ); return SampleAnimation(controller: controller); } ݺͼग़͠ଆ͸controller੍͚ͩޚ͢Ε͹Α͍ɻ
  71. AnimatedBuilder ͰϦϑΝΫλϦϯά

  72. ͜͜·Ͱͷ໰୊఺ setState()ΛݺͿͨΊ͚ͩʹListenerΛ ηοτ͍ͯ͠Δ৑௕ͳίʔυ͕͋Δɻ

  73. @override initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds:

    2000), vsync: this) ..addListener(() { setState(() {}); }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); controller.forward(); }
  74. @override initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds:

    2000), vsync: this) ..addListener(() { setState(() {}); }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); controller.forward(); } ࠶ඳը͢ΔͨΊʹListenerΛηοτͯ͠ setState()ΛݺͿ৑௕ͳίʔυɻ => AnimatedBuilderΛ࢖ͬͯলུՄೳɻ
  75. AnimatedBuilder - controllerͷมߋΛݕ஌ͯ͠࠶ඳը͠௚͢ AnimatedWidgetΛܧঝ͍ͯ͠Δ - builderͱcontrollerΛҾ਺ʹ౉ͯ͠ WidgetΛ૊ΈཱͯΔ

  76. class SampleAnimation extends StatelessWidget { .. Widget _buildAnimation(BuildContext context, Widget

    child) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } @override Widget build(BuildContext context) { return AnimatedBuilder( builder: _buildAnimation, animation: controller, ); } }
  77. class SampleAnimation extends StatelessWidget { .. Widget _buildAnimation(BuildContext context, Widget

    child) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } @override Widget build(BuildContext context) { return AnimatedBuilder( builder: _buildAnimation, animation: controller, ); } } buildϝιουͷதͰ AnimatedBuilderΛฦ͢ɻ
  78. class SampleAnimation extends StatelessWidget { .. Widget _buildAnimation(BuildContext context, Widget

    child) { return Center( child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration(color: colorAnimation.value), ), ); } @override Widget build(BuildContext context) { return AnimatedBuilder( builder: _buildAnimation, animation: controller, ); } } builderʹ͸WidgetΛੜ੒͢Δؔ਺Λ౉͢ɻ
  79. class _BasicAnimationAppState extends State<BasicAnimationApp> with SingleTickerProviderStateMixin { .. @override initState()

    { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this) // ..addListener(() { // setState(() {}); // }) .. } ݺͼग़͠ݩͰ͸ addListenerͱsetState͕ෆཁʹɻ
  80. AnimatedWidget ͱ AnimatedBuilder ͷ࢖͍෼͚ /// A general-purpose widget for building

    animations. /// /// AnimatedBuilder is useful for more complex widgets that wish to include /// an animation as part of a larger build function. To use AnimatedBuilder, /// simply construct the widget and pass it a builder function. /// /// For simple cases without additional state, consider using /// [AnimatedWidget]. /// /// ## Performance optimizations /// /// If your [builder] function contains a subtree that does not depend on the /// animation, it's more efficient to build that subtree once instead of /// rebuilding it on every animation tick. /// /// If you pass the pre-built subtree as the [child] parameter, the /// AnimatedBuilder will pass it back to your builder function so that you /// can incorporate it into your build. /// /// Using this pre-built child is entirely optional, but can improve /// performance significantly in some cases and is therefore a good practice.
  81. AnimatedWidget ͱ AnimatedBuilder ͷ࢖͍෼͚ /// A general-purpose widget for building

    animations. /// /// AnimatedBuilder is useful for more complex widgets that wish to include /// an animation as part of a larger build function. To use AnimatedBuilder, /// simply construct the widget and pass it a builder function. /// /// For simple cases without additional state, consider using /// [AnimatedWidget]. /// /// ## Performance optimizations /// /// If your [builder] function contains a subtree that does not depend on the /// animation, it's more efficient to build that subtree once instead of /// rebuilding it on every animation tick. /// /// If you pass the pre-built subtree as the [child] parameter, the /// AnimatedBuilder will pass it back to your builder function so that you /// can incorporate it into your build. /// /// Using this pre-built child is entirely optional, but can improve /// performance significantly in some cases and is therefore a good practice. builderͷඞཁͷͳ͍γϯϓϧͳWidgetͷ ৔߹ʹ͸ɺAnimatedWidgetΛ࢖͏ͷ͕Α͍ɻ Ξχϝʔγϣϯ͠ͳ͍WidgetΛؚΉ৔߹ʹ͸ɺ AnimatedBuilderΛ࢖͏ํ͕ແବͳ࠶ඳըΛ͠ ͳ͍ͷͰύϑΥʔϚϯε͕Α͍ɻ
  82. AnimatedWidget - RelativePositionedTransition - SlideTransition - SizeTransition - ScaleTransition -

    DecoratedBoxTransition - RotationTransition - PositionedTransition - AlignTransition
  83. AnimatedBuilder - BottomSheet - ExpansionTile - PopupMenu - ProgressIndicator -

    RefreshIndicator - Scaffold - SnackBar - TabBar - TextField
  84. ࿈ଓͨ͠ ΞχϝʔγϣϯΛ࡞Δ

  85. ॱ൪ʹΞχϝʔγϣϯ ੨͔ΒԫʹมԽ͠ͳ͕Β େ͖͞΋มԽ͢Δ " େ͖͕͞มԽ͔ͯ͠Β ੨͔ΒԫʹมԽ͢Δ

  86. IntervalΛ࢖͏ - CurveΛܧঝͨ͠Ϋϥε - 0.0 ~ 1.0ͷؒͰΞχϝʔγϣϯͷ։࢝ͱऴ ྃλΠϛϯάΛࢦఆ͢Δ

  87. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve: Interval(0.0, 0.5, curve: Curves.ease), // curve: Curves.ease, ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.5, 0.9, curve: Curves.ease), // curve: Curves.ease, ), ), super(key: key);
  88. class SampleAnimation extends StatelessWidget { SampleAnimation({Key key, this.controller}) : sizeAnimation

    = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve: Interval(0.0, 0.5, curve: Curves.ease), // curve: Curves.ease, ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.5, 0.9, curve: Curves.ease), // curve: Curves.ease, ), ), super(key: key); 0 ~ 1000msͷؒͰΞχϝʔγϣϯ 1000 ~ 1800msͷؒͰΞχϝʔγϣϯ
  89. None
  90. ಉ͡΍ΓํͰ૊Έ߹ΘͤΒΕΔ TJ[F d DPMPS d SPUBUF d SBEJVT d OPOF

    d     
  91. sizeAnimation = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve:

    Interval(0.0, 0.3, curve: Curves.ease), ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.3, 0.7, curve: Curves.ease), ), ), rotateAnimation = Tween<double>(begin: 0.0, end: 0.75).animate( CurvedAnimation( parent: controller, curve: Interval(0.4, 0.7, curve: Curves.ease), ), ), borderRadiusAnimation = BorderRadiusTween( begin: BorderRadius.circular(0.0), end: BorderRadius.circular(150.0), ).animate( CurvedAnimation( parent: controller, curve: Interval(0.7, 0.9, curve: Curves.ease), ), ),
  92. sizeAnimation = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve:

    Interval(0.0, 0.3, curve: Curves.ease), ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.3, 0.7, curve: Curves.ease), ), ), rotateAnimation = Tween<double>(begin: 0.0, end: 0.75).animate( CurvedAnimation( parent: controller, curve: Interval(0.4, 0.7, curve: Curves.ease), ), ), borderRadiusAnimation = BorderRadiusTween( begin: BorderRadius.circular(0.0), end: BorderRadius.circular(150.0), ).animate( CurvedAnimation( parent: controller, curve: Interval(0.7, 0.9, curve: Curves.ease), ), ), sizeAnimation : 0 ~ 0.6ඵͰେ͖͘ͳΔɻ
  93. sizeAnimation = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve:

    Interval(0.0, 0.3, curve: Curves.ease), ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.3, 0.7, curve: Curves.ease), ), ), rotateAnimation = Tween<double>(begin: 0.0, end: 0.75).animate( CurvedAnimation( parent: controller, curve: Interval(0.4, 0.7, curve: Curves.ease), ), ), borderRadiusAnimation = BorderRadiusTween( begin: BorderRadius.circular(0.0), end: BorderRadius.circular(150.0), ).animate( CurvedAnimation( parent: controller, curve: Interval(0.7, 0.9, curve: Curves.ease), ), ), colorAnimation : 0.6 ~ 1.4ඵͰ৭Λม͑Δɻ rotateAnimation : 0.8 ~ 1.4ඵͰ270౓ճస͢Δɻ
  94. sizeAnimation = Tween<double>(begin: 0.0, end: 300.0).animate( CurvedAnimation( parent: controller, curve:

    Interval(0.0, 0.3, curve: Curves.ease), ), ), colorAnimation = ColorTween(begin: Colors.blue[400], end: Colors.yellow[400]) .animate( CurvedAnimation( parent: controller, curve: Interval(0.3, 0.7, curve: Curves.ease), ), ), rotateAnimation = Tween<double>(begin: 0.0, end: 0.75).animate( CurvedAnimation( parent: controller, curve: Interval(0.4, 0.7, curve: Curves.ease), ), ), borderRadiusAnimation = BorderRadiusTween( begin: BorderRadius.circular(0.0), end: BorderRadius.circular(150.0), ).animate( CurvedAnimation( parent: controller, curve: Interval(0.7, 0.9, curve: Curves.ease), ), ), borderRadiusAnimation : 1.4 ~ 1.8ඵͰ˘Λ˓ʹมԽͤ͞Δɻ
  95. Widget _buildAnimation(BuildContext context, Widget child) { return Center( child: Transform(

    transform: Matrix4.rotationZ(rotateAnimation.value * math.pi * 2.0), alignment: Alignment.center, child: Container( width: sizeAnimation.value, height: sizeAnimation.value, decoration: BoxDecoration( color: colorAnimation.value, borderRadius: borderRadiusAnimation.value), ), ), ); } ֤animationͷ஋Λ࢖ͬͯWidgetπϦʔΛߏஙɻ
  96. None
  97. ·ͱΊ

  98. AnimationController Ξχϝʔγϣϯͷ࣌ؒ΍ ։࢝ɾऴྃͳͲΛ੍ޚ͢Δɻ

  99. Tween ΞχϝʔγϣϯͰมߋ͢Δ ஋(0.0 ~ 0.1)Λɺผͷ਺ ࣈ΍৭ͳͲͷ஋ʹม׵͢Δɻ

  100. CurvedAnimation ΞχϝʔγϣϯͰมԽ͢Δ ஋ͷ؇ٸΛ͚ͭΔɻ IntervalΛ࢖͑͹࣮ߦλΠ ϛϯά΋ม͑ΒΕΔɻ

  101. AnimatedBuilder AnimationControllerͷ ஋͕มߋ͞ΕΔ͝ͱʹ ඳը͢ΔWidgetΛͭ͘ΔϏ ϧμʔɻ

  102. ΋ͬͱ஌Γ͍ͨํ͸ͪ͜Β - FlutterΞχϝʔγϣϯͷΫϥε΍֓೦ɺͦΕΒΛ૊Έ߹Θͤͨ αϯϓϧͷઆ໌
 https://flutter.io/tutorials/animation/
 https://flutter.io/animations/ - TweenͷΧελϚΠζ΍AnimatedBuilderͷೖΕࢠͳͲɺগ͠ ෳࡶͳάϥϑΞχϝʔγϣϯΛ࡞ΔνϡʔτϦΞϧ
 https://medium.com/flutter-io/zero-to-one-with-flutter-43b13fd7b354


    https://medium.com/flutter-io/zero-to-one-with-flutter-part-two- 5aa2f06655cb
  103. Thanks! Enjoy Flutter!