// 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 'package:flutter/animation.dart'; import 'basic.dart'; import 'framework.dart'; import 'package:vector_math/vector_math_64.dart'; class AnimatedBoxConstraintsValue extends AnimatedValue<BoxConstraints> { AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve, Curve reverseCurve }) : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); } class AnimatedBoxDecorationValue extends AnimatedValue<BoxDecoration> { AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve, Curve reverseCurve }) : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); BoxDecoration lerp(double t) => BoxDecoration.lerp(begin, end, t); } class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> { AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve, Curve reverseCurve }) : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t); } class AnimatedMatrix4Value extends AnimatedValue<Matrix4> { AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve, Curve reverseCurve }) : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); Matrix4 lerp(double t) { // TODO(mpcomplete): Animate the full matrix. Will animating the cells // separately work? Vector3 beginT = begin.getTranslation(); Vector3 endT = end.getTranslation(); Vector3 lerpT = beginT*(1.0-t) + endT*t; return new Matrix4.identity()..translate(lerpT); } } class AnimatedContainer extends StatefulComponent { AnimatedContainer({ Key key, this.child, this.constraints, this.decoration, this.foregroundDecoration, this.margin, this.padding, this.transform, this.width, this.height, this.curve: Curves.linear, this.duration }) : super(key: key) { assert(margin == null || margin.isNonNegative); assert(padding == null || padding.isNonNegative); assert(curve != null); assert(duration != null); } final Widget child; final BoxConstraints constraints; final BoxDecoration decoration; final BoxDecoration foregroundDecoration; final EdgeDims margin; final EdgeDims padding; final Matrix4 transform; final double width; final double height; final Curve curve; final Duration duration; _AnimatedContainerState createState() => new _AnimatedContainerState(); } class _AnimatedContainerState extends State<AnimatedContainer> { AnimatedBoxConstraintsValue _constraints; AnimatedBoxDecorationValue _decoration; AnimatedBoxDecorationValue _foregroundDecoration; AnimatedEdgeDimsValue _margin; AnimatedEdgeDimsValue _padding; AnimatedMatrix4Value _transform; AnimatedValue<double> _width; AnimatedValue<double> _height; Performance _performance; void initState() { super.initState(); _performance = new Performance(duration: config.duration, debugLabel: '${config.toStringShort()}') ..timing = new AnimationTiming(curve: config.curve) ..addListener(_updateAllVariables); _configAllVariables(); } void didUpdateConfig(AnimatedContainer oldConfig) { _performance ..duration = config.duration ..timing.curve = config.curve; if (_configAllVariables()) { _performance.progress = 0.0; _performance.play(); } } void dispose() { _performance.stop(); super.dispose(); } void _updateVariable(Animatable variable) { if (variable != null) _performance.updateVariable(variable); } void _updateAllVariables() { setState(() { _updateVariable(_constraints); _updateVariable(_decoration); _updateVariable(_foregroundDecoration); _updateVariable(_margin); _updateVariable(_padding); _updateVariable(_transform); _updateVariable(_width); _updateVariable(_height); }); } bool _configVariable(AnimatedValue variable, dynamic targetValue) { dynamic currentValue = variable.value; variable.end = targetValue; variable.begin = currentValue; return currentValue != targetValue; } bool _configAllVariables() { bool needsAnimation = false; if (config.constraints != null) { _constraints ??= new AnimatedBoxConstraintsValue(config.constraints); if (_configVariable(_constraints, config.constraints)) needsAnimation = true; } else { _constraints = null; } if (config.decoration != null) { _decoration ??= new AnimatedBoxDecorationValue(config.decoration); if (_configVariable(_decoration, config.decoration)) needsAnimation = true; } else { _decoration = null; } if (config.foregroundDecoration != null) { _foregroundDecoration ??= new AnimatedBoxDecorationValue(config.foregroundDecoration); if (_configVariable(_foregroundDecoration, config.foregroundDecoration)) needsAnimation = true; } else { _foregroundDecoration = null; } if (config.margin != null) { _margin ??= new AnimatedEdgeDimsValue(config.margin); if (_configVariable(_margin, config.margin)) needsAnimation = true; } else { _margin = null; } if (config.padding != null) { _padding ??= new AnimatedEdgeDimsValue(config.padding); if (_configVariable(_padding, config.padding)) needsAnimation = true; } else { _padding = null; } if (config.transform != null) { _transform ??= new AnimatedMatrix4Value(config.transform); if (_configVariable(_transform, config.transform)) needsAnimation = true; } else { _transform = null; } if (config.width != null) { _width ??= new AnimatedValue<double>(config.width); if (_configVariable(_width, config.width)) needsAnimation = true; } else { _width = null; } if (config.height != null) { _height ??= new AnimatedValue<double>(config.height); if (_configVariable(_height, config.height)) needsAnimation = true; } else { _height = null; } return needsAnimation; } Widget build(BuildContext context) { return new Container( child: config.child, constraints: _constraints?.value, decoration: _decoration?.value, foregroundDecoration: _foregroundDecoration?.value, margin: _margin?.value, padding: _padding?.value, transform: _transform?.value, width: _width?.value, height: _height?.value ); } void debugFillDescription(List<String> description) { super.debugFillDescription(description); if (_constraints != null) description.add('has constraints'); if (_decoration != null) description.add('has background'); if (_foregroundDecoration != null) description.add('has foreground'); if (_margin != null) description.add('has margin'); if (_padding != null) description.add('has padding'); if (_transform != null) description.add('has transform'); if (_width != null) description.add('has width'); if (_height != null) description.add('has height'); } }