您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

241 行
8.7 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using RSG.Promises;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
namespace Unity.UIWidgets.widgets {
class _ChildEntry {
public _ChildEntry(
AnimationController controller,
Animation<float> animation,
Widget transition,
Widget widgetChild
) {
D.assert(animation != null);
D.assert(transition != null);
D.assert(controller != null);
this.controller = controller;
this.animation = animation;
this.transition = transition;
this.widgetChild = widgetChild;
}
public readonly AnimationController controller;
public readonly Animation<float> animation;
public Widget transition;
public Widget widgetChild;
public override string ToString() {
return "Entry#${shortHash(this)}($widgetChild)";
}
}
public delegate Widget AnimatedSwitcherTransitionBuilder(Widget child, Animation<float> animation);
public delegate Widget AnimatedSwitcherLayoutBuilder(Widget currentChild, List<Widget> previousChildren);
public class AnimatedSwitcher : StatefulWidget {
public AnimatedSwitcher(
Key key = null,
Widget child = null,
TimeSpan? duration = null,
Curve switchInCurve = null,
Curve switchOutCurve = null,
AnimatedSwitcherTransitionBuilder transitionBuilder = null,
AnimatedSwitcherLayoutBuilder layoutBuilder = null
) : base(key: key) {
D.assert(duration != null);
this.switchInCurve = switchInCurve ?? Curves.linear;
this.switchOutCurve = switchOutCurve ?? Curves.linear;
this.transitionBuilder = transitionBuilder ?? defaultTransitionBuilder;
this.layoutBuilder = layoutBuilder ?? defaultLayoutBuilder;
this.child = child;
this.duration = duration;
}
public readonly Widget child;
public readonly TimeSpan? duration;
public readonly Curve switchInCurve;
public readonly Curve switchOutCurve;
public readonly AnimatedSwitcherTransitionBuilder transitionBuilder;
public readonly AnimatedSwitcherLayoutBuilder layoutBuilder;
public override State createState() {
return new _AnimatedSwitcherState();
}
public static Widget defaultTransitionBuilder(Widget child, Animation<float> animation) {
return new FadeTransition(
opacity: animation,
child: child
);
}
public static Widget defaultLayoutBuilder(Widget currentChild, List<Widget> previousChildren) {
List<Widget> children = previousChildren;
if (currentChild != null) {
children = children.ToList();
children.Add(currentChild);
}
return new Stack(
children: children,
alignment: Alignment.center
);
}
}
class _AnimatedSwitcherState : TickerProviderStateMixin<AnimatedSwitcher> {
_ChildEntry _currentEntry;
HashSet<_ChildEntry> _outgoingEntries = new HashSet<_ChildEntry>();
List<Widget> _outgoingWidgets = new List<Widget>();
int _childNumber = 0;
public override void initState() {
base.initState();
this._addEntryForNewChild(animate: false);
}
public override void didUpdateWidget(StatefulWidget _oldWidget) {
base.didUpdateWidget(_oldWidget);
AnimatedSwitcher oldWidget = _oldWidget as AnimatedSwitcher;
if (this.widget.transitionBuilder != oldWidget.transitionBuilder) {
this._outgoingEntries.Each(this._updateTransitionForEntry);
if (this._currentEntry != null) {
this._updateTransitionForEntry(this._currentEntry);
}
this._markChildWidgetCacheAsDirty();
}
bool hasNewChild = this.widget.child != null;
bool hasOldChild = this._currentEntry != null;
if (hasNewChild != hasOldChild ||
hasNewChild && !Widget.canUpdate(this.widget.child, this._currentEntry.widgetChild)) {
this._childNumber += 1;
this._addEntryForNewChild(animate: true);
}
else if (this._currentEntry != null) {
D.assert(hasOldChild && hasNewChild);
D.assert(Widget.canUpdate(this.widget.child, this._currentEntry.widgetChild));
this._currentEntry.widgetChild = this.widget.child;
this._updateTransitionForEntry(this._currentEntry);
this._markChildWidgetCacheAsDirty();
}
}
void _addEntryForNewChild(bool animate) {
D.assert(animate || this._currentEntry == null);
if (this._currentEntry != null) {
D.assert(animate);
D.assert(!this._outgoingEntries.Contains(this._currentEntry));
this._outgoingEntries.Add(this._currentEntry);
this._currentEntry.controller.reverse();
this._markChildWidgetCacheAsDirty();
this._currentEntry = null;
}
if (this.widget.child == null) {
return;
}
AnimationController controller = new AnimationController(
duration: this.widget.duration,
vsync: this
);
Animation<float> animation = new CurvedAnimation(
parent: controller,
curve: this.widget.switchInCurve,
reverseCurve: this.widget.switchOutCurve
);
this._currentEntry = this._newEntry(
child: this.widget.child,
controller: controller,
animation: animation,
builder: this.widget.transitionBuilder
);
if (animate) {
controller.forward();
}
else {
D.assert(this._outgoingEntries.isEmpty);
controller.setValue(1.0f);
}
}
_ChildEntry _newEntry(
Widget child,
AnimatedSwitcherTransitionBuilder builder,
AnimationController controller,
Animation<float> animation
) {
_ChildEntry entry = new _ChildEntry(
widgetChild: child,
transition: KeyedSubtree.wrap(builder(child, animation), this._childNumber),
animation: animation,
controller: controller
);
animation.addStatusListener((AnimationStatus status) => {
if (status == AnimationStatus.dismissed) {
this.setState(() => {
D.assert(this.mounted);
D.assert(this._outgoingEntries.Contains(entry));
this._outgoingEntries.Remove(entry);
this._markChildWidgetCacheAsDirty();
});
controller.dispose();
}
});
return entry;
}
void _markChildWidgetCacheAsDirty() {
this._outgoingWidgets = null;
}
void _updateTransitionForEntry(_ChildEntry entry) {
entry.transition = new KeyedSubtree(
key: entry.transition.key,
child: this.widget.transitionBuilder(entry.widgetChild, entry.animation)
);
}
void _rebuildOutgoingWidgetsIfNeeded() {
this._outgoingWidgets = this._outgoingWidgets ?? new List<Widget>(
this._outgoingEntries.Select((_ChildEntry entry) => entry.transition)
);
D.assert(this._outgoingEntries.Count == this._outgoingWidgets.Count);
D.assert(this._outgoingEntries.isEmpty() ||
this._outgoingEntries.Last().transition == this._outgoingWidgets.Last());
}
public override void dispose() {
if (this._currentEntry != null) {
this._currentEntry.controller.dispose();
}
foreach (_ChildEntry entry in this._outgoingEntries) {
entry.controller.dispose();
}
base.dispose();
}
public override Widget build(BuildContext context) {
this._rebuildOutgoingWidgetsIfNeeded();
return this.widget.layoutBuilder(this._currentEntry?.transition, this._outgoingWidgets);
}
}
}