using Unity.UIWidgets.animation; using Unity.UIWidgets.foundation; using Unity.UIWidgets.painting; using Unity.UIWidgets.rendering; using Unity.UIWidgets.ui; using UnityEngine; using Rect = Unity.UIWidgets.ui.Rect; namespace Unity.UIWidgets.widgets { public abstract class AnimatedWidget : StatefulWidget { public readonly Listenable listenable; protected AnimatedWidget(Key key = null, Listenable listenable = null) : base(key) { D.assert(listenable != null); this.listenable = listenable; } protected internal abstract Widget build(BuildContext context); public override State createState() { return new _AnimatedState(); } public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.add(new DiagnosticsProperty("animation", this.listenable)); } } public class _AnimatedState : State { public override void initState() { base.initState(); this.widget.listenable.addListener(this._handleChange); } public override void didUpdateWidget(StatefulWidget oldWidget) { base.didUpdateWidget(oldWidget); if (this.widget.listenable != ((AnimatedWidget) oldWidget).listenable) { ((AnimatedWidget) oldWidget).listenable.removeListener(this._handleChange); this.widget.listenable.addListener(this._handleChange); } } public override void dispose() { this.widget.listenable.removeListener(this._handleChange); base.dispose(); } void _handleChange() { this.setState(() => { // The listenable's state is our build state, and it changed already. }); } public override Widget build(BuildContext context) { return this.widget.build(context); } } public class SlideTransition : AnimatedWidget { public SlideTransition(Key key = null, Animation position = null, bool transformHitTests = true, TextDirection? textDirection = null, Widget child = null) : base(key: key, listenable: position) { D.assert(position != null); this.transformHitTests = transformHitTests; this.textDirection = textDirection; this.child = child; } public Animation position { get { return (Animation) this.listenable; } } public readonly TextDirection? textDirection; public readonly bool transformHitTests; public readonly Widget child; protected internal override Widget build(BuildContext context) { var offset = this.position.value; if (this.textDirection == TextDirection.rtl) { offset = new Offset(-offset.dx, offset.dy); } return new FractionalTranslation( translation: offset, transformHitTests: this.transformHitTests, child: this.child ); } } public class ScaleTransition : AnimatedWidget { public ScaleTransition( Key key = null, Animation scale = null, Alignment alignment = null, Widget child = null ) : base(key: key, listenable: scale) { alignment = alignment ?? Alignment.center; D.assert(scale != null); this.alignment = alignment; this.child = child; } public Animation scale { get { return (Animation) this.listenable; } } public readonly Alignment alignment; public readonly Widget child; protected internal override Widget build(BuildContext context) { float scaleValue = this.scale.value; Matrix3 transform = Matrix3.makeScale(scaleValue, scaleValue); return new Transform( transform: transform, alignment: this.alignment, child: this.child ); } } public class RotationTransition : AnimatedWidget { public RotationTransition( Key key = null, Animation turns = null, Alignment alignment = null, Widget child = null) : base(key: key, listenable: turns) { D.assert(turns != null); this.alignment = alignment ?? Alignment.center; this.child = child; } public Animation turns { get { return (Animation) this.listenable; } } public readonly Alignment alignment; public readonly Widget child; protected internal override Widget build(BuildContext context) { float turnsValue = this.turns.value; Matrix3 transform = Matrix3.makeRotate((turnsValue * Mathf.PI * 2.0f)); return new Transform( transform: transform, alignment: this.alignment, child: this.child); } } public class SizeTransition : AnimatedWidget { public SizeTransition( Key key = null, Axis axis = Axis.vertical, Animation sizeFactor = null, float axisAlignment = 0.0f, Widget child = null) : base(key: key, listenable: sizeFactor) { D.assert(sizeFactor != null); this.axis = axis; this.axisAlignment = axisAlignment; this.child = child; } public readonly Axis axis; public readonly float axisAlignment; Animation sizeFactor { get { return (Animation) this.listenable; } } public readonly Widget child; protected internal override Widget build(BuildContext context) { Alignment alignment; if (this.axis == Axis.vertical) { alignment = new Alignment(-1.0f, this.axisAlignment); } else { alignment = new Alignment(this.axisAlignment, -1.0f); } return new ClipRect( child: new Align( alignment: alignment, widthFactor: this.axis == Axis.horizontal ? (float?) Mathf.Max(this.sizeFactor.value, 0.0f) : null, heightFactor: this.axis == Axis.vertical ? (float?) Mathf.Max(this.sizeFactor.value, 0.0f) : null, child: this.child ) ); } } public class FadeTransition : SingleChildRenderObjectWidget { public FadeTransition(Key key = null, Animation opacity = null, Widget child = null) : base(key: key, child: child) { D.assert(opacity != null); this.opacity = opacity; } public readonly Animation opacity; public override RenderObject createRenderObject(BuildContext context) { return new RenderAnimatedOpacity( opacity: this.opacity ); } public override void updateRenderObject(BuildContext context, RenderObject renderObject) { ((RenderAnimatedOpacity) renderObject).opacity = this.opacity; } public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.add(new DiagnosticsProperty>("opacity", this.opacity)); } } public class RelativeRectTween : Tween { public RelativeRectTween(RelativeRect begin = null, RelativeRect end = null) : base(begin: begin, end: end) { } public override RelativeRect lerp(float t) { return RelativeRect.lerp(this.begin, this.end, t); } } public class PositionedTransition : AnimatedWidget { public PositionedTransition( Key key = null, Animation rect = null, Widget child = null ) : base(key: key, listenable: rect) { D.assert(rect != null); D.assert(child != null); this.child = child; } Animation rect { get { return (Animation) this.listenable; } } public readonly Widget child; protected internal override Widget build(BuildContext context) { return Positioned.fromRelativeRect( rect: this.rect.value, child: this.child ); } } public class RelativePositionedTransition : AnimatedWidget { public RelativePositionedTransition( Key key = null, Animation rect = null, Size size = null, Widget child = null ) : base(key: key, listenable: rect) { D.assert(rect != null); D.assert(size != null); D.assert(child != null); this.size = size; this.child = child; } Animation rect { get { return (Animation) this.listenable; } } public readonly Size size; public readonly Widget child; protected internal override Widget build(BuildContext context) { RelativeRect offsets = RelativeRect.fromSize(this.rect.value, this.size); return new Positioned( top: offsets.top, right: offsets.right, bottom: offsets.bottom, left: offsets.left, child: this.child ); } } public class DecoratedBoxTransition : AnimatedWidget { public DecoratedBoxTransition( Key key = null, Animation decoration = null, DecorationPosition position = DecorationPosition.background, Widget child = null ) : base(key: key, listenable: decoration) { D.assert(decoration != null); D.assert(child != null); this.decoration = decoration; this.position = position; this.child = child; } public readonly Animation decoration; public readonly DecorationPosition position; public readonly Widget child; protected internal override Widget build(BuildContext context) { return new DecoratedBox( decoration: this.decoration.value, position: this.position, child: this.child ); } } public class AlignTransition : AnimatedWidget { public AlignTransition( Key key = null, Animation alignment = null, Widget child = null, float? widthFactor = null, float? heightFactor = null ) : base(key: key, listenable: alignment) { D.assert(alignment != null); D.assert(child != null); this.child = child; this.widthFactor = widthFactor; this.heightFactor = heightFactor; } Animation alignment { get { return (Animation) this.listenable; } } public readonly float? widthFactor; public readonly float? heightFactor; public readonly Widget child; protected internal override Widget build(BuildContext context) { return new Align( alignment: this.alignment.value, widthFactor: this.widthFactor, heightFactor: this.heightFactor, child: this.child ); } } public class AnimatedBuilder : AnimatedWidget { public readonly TransitionBuilder builder; public readonly Widget child; public AnimatedBuilder(Key key = null, Listenable animation = null, TransitionBuilder builder = null, Widget child = null) : base(key, animation) { D.assert(builder != null); D.assert(animation != null); this.builder = builder; this.child = child; } protected internal override Widget build(BuildContext context) { return this.builder(context, this.child); } } }