// Copyright 2015 The Chromium Authors. 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:async'; import 'package:flutter/animation.dart'; import 'basic.dart'; import 'framework.dart'; class SmoothlyResizingOverflowBox extends StatefulComponent { SmoothlyResizingOverflowBox({ Key key, this.child, this.size, this.duration, this.curve: Curves.linear }) : super(key: key) { assert(duration != null); assert(curve != null); } final Widget child; final Size size; final Duration duration; final Curve curve; _SmoothlyResizingOverflowBoxState createState() => new _SmoothlyResizingOverflowBoxState(); } class _SmoothlyResizingOverflowBoxState extends State<SmoothlyResizingOverflowBox> { ValuePerformance<Size> _size; void initState() { super.initState(); _size = new ValuePerformance( variable: new AnimatedSizeValue(config.size, curve: config.curve), duration: config.duration )..addListener(() { setState(() {}); }); } void didUpdateConfig(SmoothlyResizingOverflowBox oldConfig) { _size.duration = config.duration; _size.variable.curve = config.curve; if (config.size != oldConfig.size) { AnimatedSizeValue variable = _size.variable; variable.begin = variable.value; variable.end = config.size; _size.progress = 0.0; _size.play(); } } void dispose() { _size.stop(); super.dispose(); } Widget build(BuildContext context) { return new SizedOverflowBox( size: _size.value, child: config.child ); } } class _Entry { _Entry({ this.child, this.enterPerformance, this.enterTransition }); final Widget child; final Performance enterPerformance; final Widget enterTransition; Size childSize = Size.zero; Performance exitPerformance; Widget exitTransition; Widget get currentTransition => exitTransition ?? enterTransition; void dispose() { enterPerformance?.stop(); exitPerformance?.stop(); } } typedef Widget TransitionBuilderCallback(PerformanceView performance, Widget child); class EnterExitTransition extends StatefulComponent { EnterExitTransition({ Key key, this.child, this.duration, this.curve: Curves.linear, this.onEnter, this.onExit }) : super(key: key) { assert(child != null); assert(duration != null); assert(curve != null); assert(onEnter != null); assert(onExit != null); } final Widget child; final Duration duration; final Curve curve; final TransitionBuilderCallback onEnter; final TransitionBuilderCallback onExit; _EnterExitTransitionState createState() => new _EnterExitTransitionState(); } class _EnterExitTransitionState extends State<EnterExitTransition> { final List<_Entry> _entries = new List<_Entry>(); void initState() { super.initState(); _entries.add(_createEnterTransition()); } _Entry _createEnterTransition() { Performance enterPerformance = new Performance(duration: config.duration)..play(); return new _Entry( child: config.child, enterPerformance: enterPerformance, enterTransition: config.onEnter(enterPerformance, new KeyedSubtree( key: new GlobalKey(), child: config.child )) ); } Future _createExitTransition(_Entry entry) async { Performance exitPerformance = new Performance(duration: config.duration); entry ..exitPerformance = exitPerformance ..exitTransition = config.onExit(exitPerformance, entry.enterTransition); await exitPerformance.play(); if (!mounted) return; setState(() { _entries.remove(entry); }); } void didUpdateConfig(EnterExitTransition oldConfig) { if (config.child.key != oldConfig.child.key) { _createExitTransition(_entries.last); _entries.add(_createEnterTransition()); } } void dispose() { for (_Entry entry in new List<_Entry>.from(_entries)) entry.dispose(); super.dispose(); } Widget build(BuildContext context) { return new SmoothlyResizingOverflowBox( size: _entries.last.childSize, duration: config.duration, curve: config.curve, child: new Stack(_entries.map((_Entry entry) { return new SizeObserver( key: new ObjectKey(entry), onSizeChanged: (Size newSize) { setState(() { entry.childSize = newSize; }); }, child: entry.currentTransition ); }).toList()) ); } }