Advertisement
Guest User

Crossfading Widgets with Resize

a guest
Oct 26th, 2017
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 5.96 KB | None | 0 0
  1. import 'dart:async';
  2. import 'dart:ui' show lerpDouble;
  3.  
  4. import 'package:flutter/scheduler.dart';
  5. import 'package:flutter/widgets.dart';
  6. import 'package:lib.widgets/model.dart';
  7.  
  8. Future<Null> main() async {
  9.   // Usually you get these from a StatefulWidget with the right mixin.  Since
  10.   // we're in main and I don't like StatefulWidgets we'll create our own.
  11.   _TickerProvider tickerProvider = new _TickerProvider();
  12.  
  13.   // Fade out animation.
  14.   AnimationController fadeOut = new AnimationController(
  15.     vsync: tickerProvider,
  16.     duration: const Duration(milliseconds: 500),
  17.   );
  18.  
  19.   // Resize animation.
  20.   AnimationController resize = new AnimationController(
  21.     vsync: tickerProvider,
  22.     duration: const Duration(milliseconds: 500),
  23.   );
  24.  
  25.   // Fade in animation.
  26.   AnimationController fadeIn = new AnimationController(
  27.     vsync: tickerProvider,
  28.     duration: const Duration(milliseconds: 500),
  29.   );
  30.  
  31.   // When fade out is done, start resizing.
  32.   fadeOut.addStatusListener((AnimationStatus status) {
  33.     if (status == AnimationStatus.completed) {
  34.       resize.forward();
  35.     }
  36.   });
  37.  
  38.   // When resizing is done, start fading in .
  39.   resize.addStatusListener((AnimationStatus status) {
  40.     if (status == AnimationStatus.completed) {
  41.       fadeIn.forward();
  42.     }
  43.   });
  44.  
  45.   // Stores sizes of A and B.
  46.   _SizeModel sizeModel = new _SizeModel();
  47.  
  48.   final double padding = 8.0;
  49.  
  50.   runApp(
  51.     new ScopedModel<_SizeModel>(
  52.       model: sizeModel,
  53.       child: new Directionality(
  54.         textDirection: TextDirection.ltr, // Needed for Stack to work.
  55.         child: new GestureDetector(
  56.           behavior: HitTestBehavior.opaque,
  57.           onTap: () {
  58.             // On tap, reset everything to the beginning and start fading out.
  59.             fadeOut.value = 0.0;
  60.             resize.value = 0.0;
  61.             fadeIn.value = 0.0;
  62.             fadeOut.forward();
  63.           },
  64.           child: new AnimatedBuilder(
  65.             animation: new Listenable.merge(<Listenable>[
  66.               fadeOut,
  67.               resize,
  68.               fadeIn,
  69.             ]),
  70.             builder: (BuildContext context, Widget child) =>
  71.                 new Stack(children: <Widget>[
  72.                   // Background.
  73.                   new Center(
  74.                     child: new ScopedModelDescendant<_SizeModel>(
  75.                       builder: (
  76.                         BuildContext context,
  77.                         Widget child,
  78.                         _SizeModel sizeModel,
  79.                       ) =>
  80.                           new Container(
  81.                             width: lerpDouble(
  82.                                   sizeModel.aSize.width,
  83.                                   sizeModel.bSize.width,
  84.                                   resize.value,
  85.                                 ) +
  86.                                 2.0 * padding,
  87.                             height: lerpDouble(
  88.                                   sizeModel.aSize.height,
  89.                                   sizeModel.bSize.height,
  90.                                   resize.value,
  91.                                 ) +
  92.                                 2.0 * padding,
  93.                             color: const Color(0xFFF0F0F0),
  94.                           ),
  95.                     ),
  96.                   ),
  97.  
  98.                   // First child.
  99.                   new Offstage(
  100.                     offstage: fadeOut.status == AnimationStatus.completed,
  101.                     child: new Center(
  102.                       child: new Opacity(
  103.                         opacity: 1.0 - fadeOut.value,
  104.                         child: new _WidgetA(
  105.                           onSizeChanged: (Size size) => sizeModel.aSize = size,
  106.                         ),
  107.                       ),
  108.                     ),
  109.                   ),
  110.  
  111.                   // Second child.
  112.                   new Offstage(
  113.                     offstage: fadeIn.status == AnimationStatus.dismissed,
  114.                     child: new Center(
  115.                       child: new Opacity(
  116.                         opacity: fadeIn.value,
  117.                         child: new _WidgetB(
  118.                           onSizeChanged: (Size size) => sizeModel.bSize = size,
  119.                         ),
  120.                       ),
  121.                     ),
  122.                   ),
  123.                 ]),
  124.           ),
  125.         ),
  126.       ),
  127.     ),
  128.   );
  129. }
  130.  
  131. class _SizeModel extends Model {
  132.   Size _aSize = Size.zero;
  133.   Size _bSize = Size.zero;
  134.  
  135.   set aSize(Size size) {
  136.     if (size != _aSize) {
  137.       _aSize = size;
  138.       notifyListeners();
  139.     }
  140.   }
  141.  
  142.   set bSize(Size size) {
  143.     if (size != _bSize) {
  144.       _bSize = size;
  145.       notifyListeners();
  146.     }
  147.   }
  148.  
  149.   Size get aSize => _aSize;
  150.   Size get bSize => _bSize;
  151. }
  152.  
  153. class _TickerProvider extends TickerProvider {
  154.   @override
  155.   Ticker createTicker(TickerCallback onTick) {
  156.     return new Ticker(onTick);
  157.   }
  158. }
  159.  
  160. // Content of first widget goes in here.
  161. class _WidgetA extends StatelessWidget {
  162.   final ValueChanged<Size> onSizeChanged;
  163.  
  164.   const _WidgetA({this.onSizeChanged});
  165.  
  166.   @override
  167.   Widget build(BuildContext context) => new Container(
  168.         width: 200.0,
  169.         height: 300.0,
  170.         child: new LayoutBuilder(
  171.             builder: (BuildContext context, BoxConstraints constraints) {
  172.           onSizeChanged?.call(constraints.biggest);
  173.           return new Container(
  174.             color: const Color(0xFF00FF00),
  175.           );
  176.         }),
  177.       );
  178. }
  179.  
  180. // Content of second widget goes in here.
  181. class _WidgetB extends StatelessWidget {
  182.   final ValueChanged<Size> onSizeChanged;
  183.  
  184.   const _WidgetB({this.onSizeChanged});
  185.  
  186.   @override
  187.   Widget build(BuildContext context) => new Container(
  188.         width: 200.0,
  189.         height: 400.0,
  190.         child: new LayoutBuilder(
  191.             builder: (BuildContext context, BoxConstraints constraints) {
  192.           onSizeChanged?.call(constraints.biggest);
  193.           return new Container(
  194.             color: const Color(0xFF0000FF),
  195.           );
  196.         }),
  197.       );
  198. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement