您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
228 行
8.5 KiB
228 行
8.5 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.UIWidgets.animation;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
|
|
namespace Unity.UIWidgets.widgets {
|
|
public enum CrossFadeState {
|
|
showFirst,
|
|
showSecond
|
|
}
|
|
|
|
public delegate Widget AnimatedCrossFadeBuilder(Widget topChild, Key topChildKey, Widget bottomChild,
|
|
Key bottomChildKey);
|
|
|
|
|
|
public class AnimatedCrossFade : StatefulWidget {
|
|
public AnimatedCrossFade(
|
|
Key key = null,
|
|
Widget firstChild = null,
|
|
Widget secondChild = null,
|
|
Curve firstCurve = null,
|
|
Curve secondCurve = null,
|
|
Curve sizeCurve = null,
|
|
Alignment alignment = null,
|
|
CrossFadeState? crossFadeState = null,
|
|
TimeSpan? duration = null,
|
|
AnimatedCrossFadeBuilder layoutBuilder = null
|
|
) : base(key: key) {
|
|
D.assert(firstChild != null);
|
|
D.assert(secondChild != null);
|
|
D.assert(crossFadeState != null);
|
|
D.assert(duration != null);
|
|
this.firstChild = firstChild;
|
|
this.secondChild = secondChild;
|
|
this.firstCurve = firstCurve ?? Curves.linear;
|
|
this.secondCurve = secondCurve ?? Curves.linear;
|
|
this.sizeCurve = sizeCurve ?? Curves.linear;
|
|
this.alignment = alignment ?? Alignment.topCenter;
|
|
this.crossFadeState = crossFadeState ?? CrossFadeState.showFirst;
|
|
this.duration = duration ?? TimeSpan.Zero;
|
|
this.layoutBuilder = layoutBuilder ?? defaultLayoutBuilder;
|
|
}
|
|
|
|
public readonly Widget firstChild;
|
|
|
|
public readonly Widget secondChild;
|
|
|
|
public readonly CrossFadeState crossFadeState;
|
|
|
|
public readonly TimeSpan duration;
|
|
|
|
public readonly Curve firstCurve;
|
|
|
|
public readonly Curve secondCurve;
|
|
|
|
public readonly Curve sizeCurve;
|
|
|
|
public readonly Alignment alignment;
|
|
|
|
public readonly AnimatedCrossFadeBuilder layoutBuilder;
|
|
|
|
static Widget defaultLayoutBuilder(Widget topChild, Key topChildKey, Widget bottomChild, Key bottomChildKey) {
|
|
return new Stack(
|
|
overflow: Overflow.visible,
|
|
children: new List<Widget> {
|
|
new Positioned(
|
|
key: bottomChildKey,
|
|
left: 0.0f,
|
|
top: 0.0f,
|
|
right: 0.0f,
|
|
child: bottomChild),
|
|
new Positioned(
|
|
key: topChildKey,
|
|
child: topChild)
|
|
}
|
|
);
|
|
}
|
|
|
|
public override State createState() {
|
|
return new _AnimatedCrossFadeState();
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new EnumProperty<CrossFadeState>("crossFadeState", this.crossFadeState));
|
|
properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment,
|
|
defaultValue: Alignment.topCenter));
|
|
}
|
|
}
|
|
|
|
|
|
public class _AnimatedCrossFadeState : TickerProviderStateMixin<AnimatedCrossFade> {
|
|
AnimationController _controller;
|
|
Animation<float> _firstAnimation;
|
|
Animation<float> _secondAnimation;
|
|
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
this._controller = new AnimationController(duration: this.widget.duration, vsync: this);
|
|
if (this.widget.crossFadeState == CrossFadeState.showSecond) {
|
|
this._controller.setValue(1.0f);
|
|
}
|
|
|
|
this._firstAnimation = this._initAnimation(this.widget.firstCurve, true);
|
|
this._secondAnimation = this._initAnimation(this.widget.secondCurve, false);
|
|
this._controller.addStatusListener((AnimationStatus status) => { this.setState(() => { }); });
|
|
}
|
|
|
|
Animation<float> _initAnimation(Curve curve, bool inverted) {
|
|
Animation<float> result = this._controller.drive(new CurveTween(curve: curve));
|
|
if (inverted) {
|
|
result = result.drive(new FloatTween(begin: 1.0f, end: 0.0f));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public override void dispose() {
|
|
this._controller.dispose();
|
|
base.dispose();
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget oldWidget) {
|
|
base.didUpdateWidget(oldWidget);
|
|
AnimatedCrossFade _oldWidget = (AnimatedCrossFade) oldWidget;
|
|
if (this.widget.duration != _oldWidget.duration) {
|
|
this._controller.duration = this.widget.duration;
|
|
}
|
|
|
|
if (this.widget.firstCurve != _oldWidget.firstCurve) {
|
|
this._firstAnimation = this._initAnimation(this.widget.firstCurve, true);
|
|
}
|
|
|
|
if (this.widget.secondCurve != _oldWidget.secondCurve) {
|
|
this._secondAnimation = this._initAnimation(this.widget.secondCurve, false);
|
|
}
|
|
|
|
if (this.widget.crossFadeState != _oldWidget.crossFadeState) {
|
|
switch (this.widget.crossFadeState) {
|
|
case CrossFadeState.showFirst:
|
|
this._controller.reverse();
|
|
break;
|
|
case CrossFadeState.showSecond:
|
|
this._controller.forward();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool _isTransitioning {
|
|
get {
|
|
return this._controller.status == AnimationStatus.forward ||
|
|
this._controller.status == AnimationStatus.reverse;
|
|
}
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
Key kFirstChildKey = new ValueKey<CrossFadeState>(CrossFadeState.showFirst);
|
|
Key kSecondChildKey = new ValueKey<CrossFadeState>(CrossFadeState.showSecond);
|
|
bool transitioningForwards = this._controller.status == AnimationStatus.completed ||
|
|
this._controller.status == AnimationStatus.forward;
|
|
|
|
Key topKey;
|
|
Widget topChild;
|
|
Animation<float> topAnimation;
|
|
Key bottomKey;
|
|
Widget bottomChild;
|
|
Animation<float> bottomAnimation;
|
|
if (transitioningForwards) {
|
|
topKey = kSecondChildKey;
|
|
topChild = this.widget.secondChild;
|
|
topAnimation = this._secondAnimation;
|
|
bottomKey = kFirstChildKey;
|
|
bottomChild = this.widget.firstChild;
|
|
bottomAnimation = this._firstAnimation;
|
|
}
|
|
else {
|
|
topKey = kFirstChildKey;
|
|
topChild = this.widget.firstChild;
|
|
topAnimation = this._firstAnimation;
|
|
bottomKey = kSecondChildKey;
|
|
bottomChild = this.widget.secondChild;
|
|
bottomAnimation = this._secondAnimation;
|
|
}
|
|
|
|
bottomChild = new TickerMode(
|
|
key: bottomKey,
|
|
enabled: this._isTransitioning,
|
|
child: new FadeTransition(
|
|
opacity: bottomAnimation,
|
|
child: bottomChild
|
|
)
|
|
);
|
|
|
|
topChild = new TickerMode(
|
|
key: topKey,
|
|
enabled: true,
|
|
child: new FadeTransition(
|
|
opacity: topAnimation,
|
|
child: topChild
|
|
)
|
|
);
|
|
|
|
return new ClipRect(
|
|
child: new AnimatedSize(
|
|
alignment: this.widget.alignment,
|
|
duration: this.widget.duration,
|
|
curve: this.widget.sizeCurve,
|
|
vsync: this,
|
|
child: this.widget.layoutBuilder(topChild, topKey, bottomChild, bottomKey)
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder description) {
|
|
base.debugFillProperties(description);
|
|
description.add(new EnumProperty<CrossFadeState>("crossFadeState", this.widget.crossFadeState));
|
|
description.add(
|
|
new DiagnosticsProperty<AnimationController>("controller", this._controller, showName: false));
|
|
description.add(new DiagnosticsProperty<Alignment>("alignment", this.widget.alignment,
|
|
defaultValue: Alignment.topCenter));
|
|
}
|
|
}
|
|
}
|