浏览代码

Merge branch 'master' into 'master'

Master

See merge request upm-packages/ui-widgets/com.unity.uiwidgets!17
/main
Shenhua Gu 6 年前
当前提交
8014ae96
共有 33 个文件被更改,包括 3900 次插入49 次删除
  1. 9
      Runtime/animation/tween.cs
  2. 38
      Runtime/engine/WidgetCanvas.cs
  3. 16
      Runtime/foundation/basic_types.cs
  4. 2
      Runtime/gestures/binding.cs
  5. 6
      Runtime/promise/Promise.cs
  6. 299
      Runtime/rendering/object.mixin.gen.cs
  7. 2
      Runtime/rendering/object.mixin.njk
  8. 275
      Runtime/rendering/proxy_box.cs
  9. 6
      Runtime/rendering/proxy_box.mixin.gen.cs
  10. 6
      Runtime/rendering/proxy_box.mixin.njk
  11. 223
      Runtime/widgets/app.cs
  12. 87
      Runtime/widgets/basic.cs
  13. 5
      Runtime/widgets/binding.cs
  14. 2
      Runtime/widgets/focus_manager.cs
  15. 6
      Runtime/widgets/page_storage.cs
  16. 9
      Runtime/widgets/widget_inspector.cs
  17. 7
      Samples/UIWidgetSample/TextInputCanvas.cs
  18. 46
      Runtime/widgets/modal_barrier.cs
  19. 11
      Runtime/widgets/modal_barrier.cs.meta
  20. 786
      Runtime/widgets/navigator.cs
  21. 11
      Runtime/widgets/navigator.cs.meta
  22. 397
      Runtime/widgets/overlay.cs
  23. 11
      Runtime/widgets/overlay.cs.meta
  24. 88
      Runtime/widgets/pages.cs
  25. 11
      Runtime/widgets/pages.cs.meta
  26. 773
      Runtime/widgets/routes.cs
  27. 11
      Runtime/widgets/routes.cs.meta
  28. 131
      Runtime/widgets/transitions.cs
  29. 11
      Runtime/widgets/transitions.cs.meta
  30. 502
      Samples/UIWidgetSample/Navigation.unity
  31. 7
      Samples/UIWidgetSample/Navigation.unity.meta
  32. 144
      Samples/UIWidgetSample/NavigationCanvas.cs
  33. 11
      Samples/UIWidgetSample/NavigationCanvas.cs.meta

9
Runtime/animation/tween.cs


}
}
public class OffsetTween : Tween<Offset> {
public OffsetTween(Offset begin, Offset end) : base(begin: begin, end: end) {
}
public override Offset lerp(double t) {
return (this.begin + (this.end - this.begin) * t);
}
}
public class CurveTween : Animatable<double> {
public CurveTween(Curve curve = null) {
D.assert(curve != null);

38
Runtime/engine/WidgetCanvas.cs


using Unity.UIWidgets.async;
using System.Collections.Generic;
using Unity.UIWidgets.async;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;

this._windowAdapter = new UIWidgetWindowAdapter(this);
this._windowAdapter.OnEnable();
var root = new WidgetsApp(home: this.getWidget(), window: this._windowAdapter);
var root = new WidgetsApp(
home: this.getWidget(),
window: this._windowAdapter,
routes: this.routes,
textStyle: this.textStyle,
pageRouteBuilder: this.pageRouteBuilder,
onGenerateRoute: this.onGenerateRoute,
onUnknownRoute: this.onUnknownRoute);
protected virtual Dictionary<string, WidgetBuilder> routes => null;
protected virtual string initialRoute => null;
protected virtual RouteFactory onGenerateRoute => null;
protected virtual RouteFactory onUnknownRoute => null;
protected virtual painting.TextStyle textStyle => null;
protected virtual PageRouteFactory pageRouteBuilder => (RouteSettings settings, WidgetBuilder builder) =>
new PageRouteBuilder(
settings: settings,
pageBuilder: (BuildContext context, Unity.UIWidgets.animation.Animation<double> animation,
Unity.UIWidgets.animation.Animation<double> secondaryAnimation) => builder(context)
);
protected override void OnDisable() {
D.assert(this._windowAdapter != null);
this._windowAdapter.OnDisable();

protected abstract Widget getWidget();
protected virtual Widget getWidget() {
return null;
}
internal void applyRenderTexture(Rect screenRect, Texture texture, Material mat) {
this.texture = texture;

}
if (this._mouseEntered && (this._lastMouseMove.x != Input.mousePosition.x ||
this._lastMouseMove.y != Input.mousePosition.y)) {
this.OnMouseOver();
this.handleMouseMove();
}
this._lastMouseMove = Input.mousePosition;

}
}
void OnMouseOver() {
void handleMouseMove() {
var pos = this.getPointPosition(Input.mousePosition);
this._windowAdapter.postPointerEvent(new PointerData(
timeStamp: Timer.timespanSinceStartup,

16
Runtime/foundation/basic_types.cs


it.TryGetValue(key, out v);
return v;
}
public static T first<T>(this IList<T> it) {
return it[0];
}
public static T last<T>(this IList<T> it) {
return it[it.Count - 1];
}
public static T removeLast<T>(this IList<T> it)
{
var lastIndex = it.Count - 1;
var result = it[lastIndex];
it.RemoveAt(lastIndex);
return result;
}
}
}

2
Runtime/gestures/binding.cs


public readonly HashSet<HitTestTarget> lastMoveTargets = new HashSet<HitTestTarget>();
void _handlePointerEvent(PointerEvent evt) {
if (evt is PointerHoverEvent || evt is PointerMoveEvent) {
if (evt is PointerHoverEvent) {
this._handlePointerHoverEvent(evt);
}

6
Runtime/promise/Promise.cs


/// Gets the id of the promise, useful for referencing the promise during runtime.
/// </summary>
int Id { get; }
bool isCompleted { get; }
/// <summary>
/// Set the name of the promise, useful for debugging.

/// </summary>
public int Id {
get { return this.id; }
}
public bool isCompleted {
get { return this.CurState != PromiseState.Pending; }
}
readonly int id;

299
Runtime/rendering/object.mixin.gen.cs


}
public abstract class ContainerRenderObjectMixinRenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack<ChildType, ParentDataType> : RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack, ContainerRenderObjectMixin
where ChildType : RenderObject
where ParentDataType : ParentData, ContainerParentDataMixin<ChildType> {
bool _debugUltimatePreviousSiblingOf(ChildType child, ChildType equals = null) {
ParentDataType childParentData = (ParentDataType) child.parentData;
while (childParentData.previousSibling != null) {
D.assert(childParentData.previousSibling != child);
child = childParentData.previousSibling;
childParentData = (ParentDataType) child.parentData;
}
return child == equals;
}
bool _debugUltimateNextSiblingOf(ChildType child, ChildType equals = null) {
ParentDataType childParentData = (ParentDataType) child.parentData;
while (childParentData.nextSibling != null) {
D.assert(childParentData.nextSibling != child);
child = childParentData.nextSibling;
childParentData = (ParentDataType) child.parentData;
}
return child == equals;
}
int _childCount = 0;
public int childCount {
get { return this._childCount; }
}
public bool debugValidateChild(RenderObject child) {
D.assert(() => {
if (!(child is ChildType)) {
throw new UIWidgetsError(
"A " + this.GetType() + " expected a child of type " + typeof(ChildType) + " but received a " +
"child of type " + child.GetType() + ".\n" +
"RenderObjects expect specific types of children because they " +
"coordinate with their children during layout and paint. For " +
"example, a RenderSliver cannot be the child of a RenderBox because " +
"a RenderSliver does not understand the RenderBox layout protocol.\n" +
"\n" +
"The " + this.GetType() + " that expected a $ChildType child was created by:\n" +
" " + this.debugCreator + "\n" +
"\n" +
"The " + child.GetType() + " that did not match the expected child type " +
"was created by:\n" +
" " + child.debugCreator + "\n"
);
}
return true;
});
return true;
}
ChildType _firstChild;
ChildType _lastChild;
void _insertIntoChildList(ChildType child, ChildType after = null) {
var childParentData = (ParentDataType) child.parentData;
D.assert(childParentData.nextSibling == null);
D.assert(childParentData.previousSibling == null);
this._childCount++;
D.assert(this._childCount > 0);
if (after == null) {
childParentData.nextSibling = this._firstChild;
if (this._firstChild != null) {
var firstChildParentData = (ParentDataType) this._firstChild.parentData;
firstChildParentData.previousSibling = child;
}
this._firstChild = child;
this._lastChild = this._lastChild ?? child;
} else {
D.assert(this._firstChild != null);
D.assert(this._lastChild != null);
D.assert(this._debugUltimatePreviousSiblingOf(after, equals: this._firstChild));
D.assert(this._debugUltimateNextSiblingOf(after, equals: this._lastChild));
var afterParentData = (ParentDataType) after.parentData;
if (afterParentData.nextSibling == null) {
D.assert(after == this._lastChild);
childParentData.previousSibling = after;
afterParentData.nextSibling = child;
this._lastChild = child;
} else {
childParentData.nextSibling = afterParentData.nextSibling;
childParentData.previousSibling = after;
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;
var childNextSiblingParentData = (ParentDataType) childParentData.nextSibling.parentData;
childPreviousSiblingParentData.nextSibling = child;
childNextSiblingParentData.previousSibling = child;
D.assert(afterParentData.nextSibling == child);
}
}
}
public virtual void insert(ChildType child, ChildType after = null) {
D.assert(child != this, "A RenderObject cannot be inserted into itself.");
D.assert(after != this,
"A RenderObject cannot simultaneously be both the parent and the sibling of another RenderObject.");
D.assert(child != after, "A RenderObject cannot be inserted after itself.");
D.assert(child != this._firstChild);
D.assert(child != this._lastChild);
this.adoptChild(child);
this._insertIntoChildList(child, after);
}
public virtual void add(ChildType child) {
this.insert(child, this._lastChild);
}
public virtual void addAll(List<ChildType> children) {
if (children != null) {
children.ForEach(this.add);
}
}
public void _removeFromChildList(ChildType child) {
var childParentData = (ParentDataType) child.parentData;
D.assert(this._debugUltimatePreviousSiblingOf(child, equals: this._firstChild));
D.assert(this._debugUltimateNextSiblingOf(child, equals: this._lastChild));
D.assert(this._childCount >= 0);
if (childParentData.previousSibling == null) {
D.assert(this._firstChild == child);
this._firstChild = childParentData.nextSibling;
} else {
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;
childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
}
if (childParentData.nextSibling == null) {
D.assert(this._lastChild == child);
this._lastChild = childParentData.previousSibling;
} else {
var childNextSiblingParentData = (ParentDataType) childParentData.nextSibling.parentData;
childNextSiblingParentData.previousSibling = childParentData.previousSibling;
}
childParentData.previousSibling = null;
childParentData.nextSibling = null;
this._childCount--;
}
public virtual void remove(ChildType child) {
this._removeFromChildList(child);
this.dropChild(child);
}
public virtual void removeAll() {
ChildType child = this._firstChild;
while (child != null) {
var childParentData = (ParentDataType) child.parentData;
var next = childParentData.nextSibling;
childParentData.previousSibling = null;
childParentData.nextSibling = null;
this.dropChild(child);
child = next;
}
this._firstChild = null;
this._lastChild = null;
this._childCount = 0;
}
public void move(ChildType child, ChildType after = null) {
D.assert(child != this);
D.assert(after != this);
D.assert(child != after);
D.assert(child.parent == this);
var childParentData = (ParentDataType) child.parentData;
if (childParentData.previousSibling == after) {
return;
}
this._removeFromChildList(child);
this._insertIntoChildList(child, after);
this.markNeedsLayout();
}
public override void attach(object owner) {
base.attach(owner);
ChildType child = this._firstChild;
while (child != null) {
child.attach(owner);
var childParentData = (ParentDataType) child.parentData;
child = childParentData.nextSibling;
}
}
public override void detach() {
base.detach();
ChildType child = this._firstChild;
while (child != null) {
child.detach();
var childParentData = (ParentDataType) child.parentData;
child = childParentData.nextSibling;
}
}
public override void redepthChildren() {
ChildType child = this._firstChild;
while (child != null) {
this.redepthChild(child);
var childParentData = (ParentDataType) child.parentData;
child = childParentData.nextSibling;
}
}
public override void visitChildren(RenderObjectVisitor visitor) {
ChildType child = this._firstChild;
while (child != null) {
visitor(child);
var childParentData = (ParentDataType) child.parentData;
child = childParentData.nextSibling;
}
}
public ChildType firstChild {
get { return this._firstChild; }
}
public ChildType lastChild {
get { return this._lastChild; }
}
public ChildType childBefore(ChildType child) {
D.assert(child != null);
D.assert(child.parent == this);
var childParentData = (ParentDataType) child.parentData;
return childParentData.previousSibling;
}
public ChildType childAfter(ChildType child) {
D.assert(child != null);
D.assert(child.parent == this);
var childParentData = (ParentDataType) child.parentData;
return childParentData.nextSibling;
}
public override List<DiagnosticsNode> debugDescribeChildren() {
var children = new List<DiagnosticsNode>();
if (this.firstChild != null) {
ChildType child = this.firstChild;
int count = 1;
while (true) {
children.Add(child.toDiagnosticsNode(name: "child " + count));
if (child == this.lastChild) {
break;
}
count += 1;
var childParentData = (ParentDataType) child.parentData;
child = childParentData.nextSibling;
}
}
return children;
}
void ContainerRenderObjectMixin.insert(RenderObject child, RenderObject after) {
this.insert((ChildType) child, (ChildType) after);
}
void ContainerRenderObjectMixin.remove(RenderObject child) {
this.remove((ChildType) child);
}
void ContainerRenderObjectMixin.move(RenderObject child, RenderObject after) {
this.move((ChildType) child, (ChildType) after);
}
RenderObject ContainerRenderObjectMixin.firstChild {
get { return this.firstChild; }
}
RenderObject ContainerRenderObjectMixin.lastChild {
get { return this.lastChild; }
}
RenderObject ContainerRenderObjectMixin.childBefore(RenderObject child) {
return this.childBefore((ChildType) child);
}
RenderObject ContainerRenderObjectMixin.childAfter(RenderObject child) {
return this.childAfter((ChildType) child);
}
}
}

2
Runtime/rendering/object.mixin.njk


{{ ContainerRenderObjectMixin('RenderSliver') }}
{{ ContainerRenderObjectMixin('RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack') }}
}

275
Runtime/rendering/proxy_box.cs


using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;

int _alpha;
static int _getAlphaFromOpacity(double opacity) {
internal static int _getAlphaFromOpacity(double opacity) {
double _opacity;
public double opacity {
get { return this._opacity; }
set {

this.markNeedsPaint();
}
}
double _opacity;
public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {

}
}
public class RenderAnimatedOpacity : RenderProxyBox {
public RenderAnimatedOpacity(
Animation<double> opacity = null,
RenderBox child = null
) : base(child) {
D.assert(opacity != null);
this.opacity = opacity;
}
int _alpha;
protected override bool alwaysNeedsCompositing => this.child != null && this._currentlyNeedsCompositing;
bool _currentlyNeedsCompositing;
Animation<double> _opacity;
public Animation<double> opacity {
get => this._opacity;
set {
D.assert(value != null);
if (this._opacity == value)
return;
if (this.attached && this._opacity != null)
this._opacity.removeListener(this._updateOpacity);
this._opacity = value;
if (this.attached)
this._opacity.addListener(this._updateOpacity);
this._updateOpacity();
}
}
public override void attach(object owner) {
base.attach(owner);
this._opacity.addListener(this._updateOpacity);
this._updateOpacity(); // in case it changed while we weren't listening
}
public override void detach() {
this._opacity.removeListener(this._updateOpacity);
base.detach();
}
public void _updateOpacity() {
var oldAlpha = this._alpha;
this._alpha = RenderOpacity._getAlphaFromOpacity(this._opacity.value.clamp(0.0, 1.0));
if (oldAlpha != this._alpha) {
bool didNeedCompositing = this._currentlyNeedsCompositing;
this._currentlyNeedsCompositing = this._alpha > 0 &&this. _alpha < 255;
if (this.child != null && didNeedCompositing != this._currentlyNeedsCompositing)
this.markNeedsCompositingBitsUpdate();
this.markNeedsPaint();
}
}
public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {
if (this._alpha == 0)
return;
if (this._alpha == 255) {
context.paintChild(this.child, offset);
return;
}
D.assert(this.needsCompositing);
context.pushOpacity(offset, this._alpha, base.paint);
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Animation<double>>("opacity", this.opacity));
}
}
public enum DecorationPosition {
background,
foreground,

}
}
public class RenderFractionalTranslation : RenderProxyBox {
public RenderFractionalTranslation(
Offset translation = null,
bool transformHitTests = true,
RenderBox child = null
) : base(child: child) {
D.assert(translation != null);
this._translation = translation;
this.transformHitTests = transformHitTests;
}
public Offset translation {
get => this._translation;
set {
D.assert(value != null);
if (this._translation == value)
return;
this._translation = value;
this.markNeedsPaint();
}
}
Offset _translation;
public override bool hitTest(HitTestResult result, Offset position) {
return this.hitTestChildren(result, position: position);
}
public bool transformHitTests;
protected override bool hitTestChildren(HitTestResult result, Offset position) {
D.assert(!this.debugNeedsLayout);
if (this.transformHitTests) {
position = new Offset(
position.dx - this.translation.dx * this.size.width,
position.dy - this.translation.dy * this.size.height
);
}
return base.hitTestChildren(result, position: position);
}
public override void paint(PaintingContext context, Offset offset) {
D.assert(!this.debugNeedsLayout);
if (this.child != null) {
base.paint(context, new Offset(
offset.dx + this.translation.dx * this.size.width,
offset.dy + this.translation.dy * this.size.height
));
}
}
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
transform.preTranslate((float)(this.translation.dx * this.size.width),
(float)(this.translation.dy * this.size.height));
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Offset>("translation", this.translation));
properties.add(new DiagnosticsProperty<bool>("transformHitTests", this.transformHitTests));
}
}
public delegate void PointerDownEventListener(PointerDownEvent evt);
public delegate void PointerMoveEventListener(PointerMoveEvent evt);

base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("ignoring", this.ignoring));
}
}
public class RenderOffstage : RenderProxyBox {
public RenderOffstage(bool offstage = true,
RenderBox child = null): base(child) {
this._offstage = offstage;
}
public bool offstage {
get => this._offstage;
set {
if (value == this._offstage) {
return;
}
this._offstage = value;
this.markNeedsLayoutForSizedByParentChange();
}
}
bool _offstage;
protected override double computeMinIntrinsicWidth(double height) {
if (this.offstage)
return 0.0;
return base.computeMinIntrinsicWidth(height);
}
protected override double computeMaxIntrinsicWidth(double height) {
if (this.offstage)
return 0.0;
return base.computeMaxIntrinsicWidth(height);
}
protected override double computeMinIntrinsicHeight(double width) {
if (this.offstage)
return 0.0;
return base.computeMinIntrinsicHeight(width);
}
protected override double computeMaxIntrinsicHeight(double width) {
if (this.offstage)
return 0.0;
return base.computeMaxIntrinsicHeight(width);
}
protected override double? computeDistanceToActualBaseline(TextBaseline baseline) {
if (this.offstage)
return null;
return base.computeDistanceToActualBaseline(baseline);
}
protected override bool sizedByParent => this.offstage;
protected override void performResize() {
D.assert(this.offstage);
this.size = this.constraints.smallest;
}
protected override void performLayout() {
if (this.offstage) {
this.child?.layout(this.constraints);
} else {
base.performLayout();
}
}
public override bool hitTest(HitTestResult result, Offset position) {
return !this.offstage && base.hitTest(result, position: position);
}
public override void paint(PaintingContext context, Offset offset) {
if (this.offstage)
return;
base.paint(context, offset);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("offstage", this.offstage));
}
public override List<DiagnosticsNode> debugDescribeChildren() {
if (this.child == null)
return new List<DiagnosticsNode>();
return new List<DiagnosticsNode> {
this.child.toDiagnosticsNode(
name: "child",
style: this.offstage ? DiagnosticsTreeStyle.offstage : DiagnosticsTreeStyle.sparse
),
};
}
}
public class RenderAbsorbPointer : RenderProxyBox {
public RenderAbsorbPointer(
RenderBox child = null,
bool absorbing = true
) : base(child)
{
this._absorbing = absorbing;
}
public bool absorbing
{
get { return this._absorbing; }
set
{
this._absorbing = value;
}
}
bool _absorbing;
public override bool hitTest(HitTestResult result, Offset position) {
return this.absorbing
? this.size.contains(position)
: base.hitTest(result, position: position);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("absorbing", this.absorbing));
}
}
}

6
Runtime/rendering/proxy_box.mixin.gen.cs


}
}
public abstract class RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack:
RenderProxyBoxMixinRenderObjectWithChildMixinRenderBox<RenderStack> {
}
}

6
Runtime/rendering/proxy_box.mixin.njk


{{ RenderProxyBoxMixin('RenderObjectWithChildMixinRenderBox') }}
}
public abstract class RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack:
RenderProxyBoxMixinRenderObjectWithChildMixinRenderBox<RenderStack> {
}
}

223
Runtime/widgets/app.cs


using System.Collections.Generic;
using RSG;
using Color = Unity.UIWidgets.ui.Color;
public delegate PageRoute PageRouteFactory(RouteSettings settings, WidgetBuilder builder);
public readonly Window window;
public readonly TransitionBuilder builder;
public readonly string initialRoute;
public readonly GlobalKey<NavigatorState> navigatorKey;
public readonly List<NavigatorObserver> navigatorObservers;
public readonly RouteFactory onGenerateRoute;
public readonly RouteFactory onUnknownRoute;
public readonly PageRouteFactory pageRouteBuilder;
public readonly Dictionary<string, WidgetBuilder> routes;
public readonly TextStyle textStyle;
public readonly Window window;
GlobalKey<NavigatorState> navigatorKey = null,
RouteFactory onGenerateRoute = null,
RouteFactory onUnknownRoute = null,
PageRouteFactory pageRouteBuilder = null,
List<NavigatorObserver> navigatorObservers = null,
string initialRoute = null,
Dictionary<string, WidgetBuilder> routes = null,
TransitionBuilder builder = null,
TextStyle textStyle = null,
this.navigatorKey = navigatorKey;
this.onGenerateRoute = onGenerateRoute;
this.onUnknownRoute = onUnknownRoute;
this.pageRouteBuilder = pageRouteBuilder;
this.routes = routes ?? new Dictionary<string, WidgetBuilder>();
this.navigatorObservers = navigatorObservers ?? new List<NavigatorObserver>();
this.initialRoute = initialRoute;
this.builder = builder;
this.textStyle = textStyle;
D.assert(
home == null ||
!this.routes.ContainsKey(Navigator.defaultRouteName),
"If the home property is specified, the routes table " +
"cannot include an entry for \" / \", since it would be redundant."
);
D.assert(
builder != null ||
home != null ||
routes.ContainsKey(Navigator.defaultRouteName) ||
onGenerateRoute != null ||
onUnknownRoute != null,
"Either the home property must be specified, " +
"or the routes table must include an entry for \"/\", " +
"or there must be on onGenerateRoute callback specified, " +
"or there must be an onUnknownRoute callback specified, " +
"or the builder property must be specified, " +
"because otherwise there is nothing to fall back on if the " +
"app is started with an intent that specifies an unknown route."
);
D.assert(
builder != null ||
onGenerateRoute != null ||
pageRouteBuilder != null,
"If neither builder nor onGenerateRoute are provided, the " +
"pageRouteBuilder must be specified so that the default handler " +
"will know what kind of PageRoute transition to build."
);
}
public override State createState() {

public class WindowProvider : InheritedWidget {
public readonly Window window;
base(key: key, child: child) {
base(key, child) {
public readonly Window window;
WindowProvider provider = (WindowProvider) context.inheritFromWidgetOfExactType(typeof(WindowProvider));
if (provider == null) {
throw new UIWidgetsError("WindowProvider is missing");
}
var provider = (WindowProvider) context.inheritFromWidgetOfExactType(typeof(WindowProvider));
if (provider == null) throw new UIWidgetsError("WindowProvider is missing");
return provider.window;
}

}
}
class _WidgetsAppState : State<WidgetsApp>, WidgetsBindingObserver {
internal class _WidgetsAppState : State<WidgetsApp>, WidgetsBindingObserver {
GlobalKey<NavigatorState> _navigator;
public IPromise<bool> didPopRoute() {
D.assert(this.mounted);
var navigator = this._navigator?.currentState;
if (navigator == null)
return Promise<bool>.Resolved(false);
return navigator.maybePop();
}
public IPromise<bool> didPushRoute(string route) {
D.assert(this.mounted);
var navigator = this._navigator?.currentState;
if (navigator == null)
return Promise<bool>.Resolved(false);
navigator.pushNamed(route);
return Promise<bool>.Resolved(true);
}
public void didChangeMetrics() {
this.setState();
}
public void didChangeTextScaleFactor() {
this.setState();
}
public void didChangeLocales(List<Locale> locale) {
// TODO: support locales.
}
this._updateNavigator();
D.assert(() => {
WidgetInspectorService.instance.inspectorShowCallback += this.inspectorShowChanged;
return true;

}
public override void didUpdateWidget(StatefulWidget oldWidget) {
base.didUpdateWidget(oldWidget);
if (this.widget.navigatorKey != ((WidgetsApp) oldWidget).navigatorKey) this._updateNavigator();
}
public override void dispose() {
WidgetsBinding.instance.removeObserver(this);

base.dispose();
}
void inspectorShowChanged() {
this.setState();
void _updateNavigator() {
this._navigator = this.widget.navigatorKey ?? new GlobalObjectKey<NavigatorState>(this);
public void didChangeMetrics() {
this.setState();
Route _onGenerateRoute(RouteSettings settings) {
var name = settings.name;
var pageContentBuilder = name == Navigator.defaultRouteName && this.widget.home != null
? context => this.widget.home
: this.widget.routes[name];
if (pageContentBuilder != null) {
D.assert(this.widget.pageRouteBuilder != null,
"The default onGenerateRoute handler for WidgetsApp must have a " +
"pageRouteBuilder set if the home or routes properties are set.");
var route = this.widget.pageRouteBuilder(
settings,
pageContentBuilder
);
D.assert(route != null,
"The pageRouteBuilder for WidgetsApp must return a valid non-null Route.");
return route;
}
if (this.widget.onGenerateRoute != null)
return this.widget.onGenerateRoute(settings);
return null;
public void didChangeTextScaleFactor() {
this.setState();
Route _onUnknownRoute(RouteSettings settings) {
D.assert(() => {
if (this.widget.onUnknownRoute == null)
throw new UIWidgetsError(
$"Could not find a generator for route {settings} in the {this.GetType()}.\n" +
$"Generators for routes are searched for in the following order:\n" +
" 1. For the \"/\" route, the \"home\" property, if non-null, is used.\n" +
" 2. Otherwise, the \"routes\" table is used, if it has an entry for " +
"the route.\n" +
" 3. Otherwise, onGenerateRoute is called. It should return a " +
"non-null value for any valid route not handled by \"home\" and \"routes\".\n" +
" 4. Finally if all else fails onUnknownRoute is called.\n" +
"Unfortunately, onUnknownRoute was not set."
);
return true;
});
var result = this.widget.onUnknownRoute(settings);
D.assert(() => {
if (result == null)
throw new UIWidgetsError(
"The onUnknownRoute callback returned null.\n" +
"When the $runtimeType requested the route $settings from its " +
"onUnknownRoute callback, the callback returned null. Such callbacks " +
"must never return null."
);
return true;
});
return result;
public void didChangeLocales(List<Locale> locale) {
// TODO: support locales.
void inspectorShowChanged() {
this.setState();
Widget result = this.widget.home;
Widget navigator = null;
if (this._navigator != null)
navigator = new Navigator(
key: this._navigator,
initialRoute: this.widget.initialRoute ?? Navigator.defaultRouteName,
onGenerateRoute: this._onGenerateRoute,
onUnknownRoute: this._onUnknownRoute,
observers: this.widget.navigatorObservers
);
Widget result;
if (this.widget.builder != null) {
result = new Builder(
builder: _context => { return this.widget.builder(_context, navigator); }
);
}
else {
D.assert(navigator != null);
result = navigator;
}
if (this.widget.textStyle != null) {
result = new DefaultTextStyle(
style: this.widget.textStyle,
child: result
);
}
if (WidgetInspectorService.instance.debugShowInspector) {
if (WidgetInspectorService.instance.debugShowInspector)
}
return true;
});

}
Widget _InspectorSelectButtonBuilder(BuildContext context, VoidCallback onPressed) {
return new _InspectorSelectButton(onPressed: onPressed);
return new _InspectorSelectButton(onPressed);
class _InspectorSelectButton : StatelessWidget {
internal class _InspectorSelectButton : StatelessWidget {
public readonly GestureTapCallback onPressed;
) : base(key: key) {
) : base(key) {
public readonly GestureTapCallback onPressed;
public override Widget build(BuildContext context) {
return new GestureDetector(

);
}
}
}
}

87
Runtime/widgets/basic.cs


}
}
public class Offstage : SingleChildRenderObjectWidget {
public Offstage(Key key = null, bool offstage = true, Widget child = null):base(key: key, child: child) {
this.offstage = offstage;
}
public readonly bool offstage;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderOffstage(offstage: this.offstage);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
((RenderOffstage)renderObject).offstage = this.offstage;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("offstage", this.offstage));
}
public override Element createElement() => new _OffstageElement(this);
}
class _OffstageElement: SingleChildRenderObjectElement {
internal _OffstageElement(Offstage widget) : base(widget) {}
new Offstage widget => (Offstage) base.widget;
public override void debugVisitOnstageChildren(ElementVisitor visitor) {
if (!this.widget.offstage)
base.debugVisitOnstageChildren(visitor);
}
}
public class AspectRatio : SingleChildRenderObjectWidget {
public AspectRatio(
Key key = null,

public static Positioned directional(Widget child, TextDirection textDirection, Key key = null,
double? start = null, double? top = null,
double? end = null, double? bottom = null, double? width = null, double? height = null) {
D.assert(textDirection != null);
double? left = null;
double? right = null;
switch (textDirection) {

}
}
public class FractionalTranslation : SingleChildRenderObjectWidget {
public FractionalTranslation(Key key = null, Offset translation = null,
bool transformHitTests = true, Widget child = null) : base(key: key, child: child) {
this.translation = translation;
this.transformHitTests = transformHitTests;
}
public readonly Offset translation;
public readonly bool transformHitTests;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderFractionalTranslation(
translation: this.translation,
transformHitTests: this.transformHitTests
);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
((RenderFractionalTranslation)renderObject).translation = this.translation;
((RenderFractionalTranslation)renderObject).transformHitTests = this.transformHitTests;
}
}
public class Align : SingleChildRenderObjectWidget {
public Align(
Key key = null,

public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("ignoring", this.ignoring));
}
}
public class AbsorbPointer : SingleChildRenderObjectWidget {
public AbsorbPointer(
Key key = null,
bool absorbing = true,
Widget child = null
) : base(key: key, child: child) {
}
public readonly bool absorbing;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderAbsorbPointer(
absorbing: this.absorbing
);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject)
{
((RenderAbsorbPointer) renderObject).absorbing = this.absorbing;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<bool>("absorbing", this.absorbing));
}
}

5
Runtime/widgets/binding.cs


using System;
using System.Collections.Generic;
using RSG;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;

void didChangeTextScaleFactor();
void didChangeLocales(List<Locale> locale);
IPromise<bool> didPopRoute();
IPromise<bool> didPushRoute(string route);
}
public class WidgetsBinding : RendererBinding {

2
Runtime/widgets/focus_manager.cs


D.assert(child != this);
D.assert(child != this._firstChild);
D.assert(child != this._lastChild);
D.assert(child == null);
D.assert(child._parent == null);
D.assert(child._manager == null);
D.assert(child._nextSibling == null);
D.assert(child._previousSibling == null);

6
Runtime/widgets/page_storage.cs


public class PageStorage : StatelessWidget {
public PageStorage(
Key key,
PageStorageBucket bucket,
Widget child
Key key = null,
PageStorageBucket bucket = null,
Widget child = null
) : base(key: key) {
D.assert(bucket != null);
this.bucket = bucket;

9
Runtime/widgets/widget_inspector.cs


using System;
using System.Collections.Generic;
using System.Linq;
using RSG;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;

}
public void didChangeLocales(List<Locale> locale) {
}
public IPromise<bool> didPopRoute() {
return Promise<bool>.Resolved(false);
}
public IPromise<bool> didPushRoute(string route) {
return Promise<bool>.Resolved(false);
}
void _selectionChangedCallback() {

7
Samples/UIWidgetSample/TextInputCanvas.cs


}
class _TextInputSampleState : State<TextInputSample> {
public class ToDoItem {
public int id;
public string content;
}
int nextId = 0;
TextEditingController titleController = new TextEditingController("");
TextEditingController descController = new TextEditingController("");
FocusNode _titleFocusNode;

46
Runtime/widgets/modal_barrier.cs


using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public class ModalBarrier : StatelessWidget {
public readonly Color color;
public readonly bool dismissible;
public ModalBarrier(Key key = null, Color color = null, bool dismissible = true) : base(key) {
this.color = color;
this.dismissible = dismissible;
}
public override Widget build(BuildContext context) {
return new GestureDetector(
onTapDown: details => {
if (this.dismissible)
Navigator.maybePop(context);
},
behavior: HitTestBehavior.opaque,
child: new ConstrainedBox(
constraints: BoxConstraints.expand(),
child: this.color == null ? null : new DecoratedBox(decoration: new BoxDecoration(this.color))
)
);
}
}
public class AnimatedModalBarrier : AnimatedWidget {
public readonly bool dismissible;
public AnimatedModalBarrier(Key key = null, Animation<Color> color = null,
bool dismissible = true) : base(key, color) {
this.dismissible = dismissible;
}
public Animation<Color> color => (Animation<Color>) this.listenable;
protected internal override Widget build(BuildContext context) {
return new ModalBarrier(color: this.color?.value, dismissible: this.dismissible);
}
}
}

11
Runtime/widgets/modal_barrier.cs.meta


fileFormatVersion: 2
guid: 57f0a2412eaef4c9496cca93496c44e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

786
Runtime/widgets/navigator.cs


using System;
using System.Collections.Generic;
using System.Linq;
using RSG;
using RSG.Promises;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
namespace Unity.UIWidgets.widgets {
public delegate Route RouteFactory(RouteSettings settings);
public delegate bool RoutePredicate(Route route);
public delegate IPromise<bool> WillPopCallback();
public enum RoutePopDisposition {
pop,
doNotPop,
bubble
}
public abstract class Route {
public readonly RouteSettings settings;
internal NavigatorState _navigator;
public Route(RouteSettings settings = null) {
this.settings = settings ?? new RouteSettings();
}
public NavigatorState navigator => this._navigator;
public virtual List<OverlayEntry> overlayEntries => new List<OverlayEntry>();
public virtual bool willHandlePopInternally => false;
public object currentResult => default;
public Promise<object> popped { get; } = new Promise<object>();
public bool isCurrent => this._navigator != null && this._navigator._history.last() == this;
public bool isFirst => this._navigator != null && this._navigator._history.first() == this;
public bool isActive => this._navigator != null && this._navigator._history.Contains(this);
protected internal virtual void install(OverlayEntry insertionPoint) {
}
protected internal virtual TickerFuture didPush() {
return TickerFutureImpl.complete();
}
protected internal virtual void didReplace(Route oldRoute) {
}
public virtual IPromise<RoutePopDisposition> willPop() {
return Promise<RoutePopDisposition>.Resolved(this.isFirst
? RoutePopDisposition.bubble
: RoutePopDisposition.pop);
}
protected internal virtual bool didPop(object result) {
this.didComplete(result);
return true;
}
protected internal virtual void didComplete(object result) {
this.popped.Resolve(result);
}
protected internal virtual void didPopNext(Route nextRoute) {
}
protected internal virtual void didChangeNext(Route nextRoute) {
}
protected internal virtual void didChangePrevious(Route previousRoute) {
}
protected internal virtual void changedInternalState() {
}
protected internal virtual void changedExternalState() {
}
protected internal virtual void dispose() {
this._navigator = null;
}
}
public class RouteSettings {
public readonly bool isInitialRoute;
public readonly string name;
public RouteSettings(string name = null, bool isInitialRoute = false) {
this.name = name;
this.isInitialRoute = isInitialRoute;
}
RouteSettings copyWith(string name = null, bool? isInitialRoute = null) {
return new RouteSettings(
name ?? this.name,
isInitialRoute ?? this.isInitialRoute
);
}
public override string ToString() {
return $"\"{this.name}\"";
}
}
public class NavigatorObserver {
internal NavigatorState _navigator;
public NavigatorState navigator => this._navigator;
public virtual void didPush(Route route, Route previousRoute) {
}
public virtual void didPop(Route route, Route previousRoute) {
}
public virtual void didRemove(Route route, Route previousRoute) {
}
public virtual void didReplace(Route newRoute = null, Route oldRoute = null) {
}
public virtual void didStartUserGesture(Route route, Route previousRoute) {
}
public virtual void didStopUserGesture() {
}
}
public class Navigator : StatefulWidget {
/// The default name for the [initialRoute].
///
/// See also:
///
/// * [dart:ui.Window.defaultRouteName], which reflects the route that the
/// application was started with.
public static string defaultRouteName = "/";
public readonly string initialRoute;
public readonly List<NavigatorObserver> observers;
public readonly RouteFactory onGenerateRoute;
public readonly RouteFactory onUnknownRoute;
public Navigator(Key key = null, string initialRoute = null,
RouteFactory onGenerateRoute = null, RouteFactory onUnknownRoute = null,
List<NavigatorObserver> observers = null) : base(key) {
D.assert(onGenerateRoute != null);
this.initialRoute = initialRoute;
this.onUnknownRoute = onUnknownRoute;
this.onGenerateRoute = onGenerateRoute;
this.observers = observers ?? new List<NavigatorObserver>();
}
public static IPromise<object> pushName(BuildContext context, string routeName) {
return of(context).pushNamed(routeName);
}
public static IPromise<object> pushReplacementNamed(BuildContext context, string routeName,
object result = null) {
return of(context).pushReplacementNamed(routeName, result);
}
public static IPromise<object> popAndPushNamed(BuildContext context, string routeName, object result = null) {
return of(context).popAndPushNamed(routeName, result);
}
public static IPromise<object> pushNamedAndRemoveUntil(BuildContext context, string newRouteName,
RoutePredicate predicate) {
return of(context).pushNamedAndRemoveUntil(newRouteName, predicate);
}
public static IPromise<object> push(BuildContext context, Route route) {
return of(context).push(route);
}
public static IPromise<object> pushReplacement(BuildContext context, Route newRoute, object result = null) {
return of(context).pushReplacement(newRoute, result);
}
public static IPromise<object> pushAndRemoveUntil(BuildContext context, Route newRoute,
RoutePredicate predicate) {
return of(context).pushAndRemoveUntil(newRoute, predicate);
}
public static void replace(BuildContext context, Route oldRoute, Route newRoute) {
of(context).replace(oldRoute, newRoute);
}
public static void replaceRouteBelow(BuildContext context, Route anchorRoute = null, Route newRoute = null) {
of(context).replaceRouteBelow(anchorRoute, newRoute);
}
public static IPromise<bool> maybePop(BuildContext context, object result = null) {
return of(context).maybePop(result);
}
public static bool pop(BuildContext context, object result = null) {
return of(context).pop(result);
}
public static void popUntil(BuildContext context, RoutePredicate predicate) {
of(context).popUntil(predicate);
}
public static void removeRoute(BuildContext context, Route route) {
of(context).removeRoute(route);
}
static void removeRouteBelow(BuildContext context, Route anchorRoute) {
of(context).removeRouteBelow(anchorRoute);
}
public static NavigatorState of(
BuildContext context,
bool rootNavigator = false,
bool nullOk = false
) {
var navigator = rootNavigator
? (NavigatorState) context.rootAncestorStateOfType(new TypeMatcher<NavigatorState>())
: (NavigatorState) context.ancestorStateOfType(new TypeMatcher<NavigatorState>());
D.assert(() => {
if (navigator == null && !nullOk)
throw new UIWidgetsError(
"Navigator operation requested with a context that does not include a Navigator.\n" +
"The context used to push or pop routes from the Navigator must be that of a " +
"widget that is a descendant of a Navigator widget."
);
return true;
});
return navigator;
}
public override State createState() {
return new NavigatorState();
}
}
public class NavigatorState : TickerProviderStateMixin<Navigator> {
internal readonly List<Route> _history = new List<Route>();
readonly GlobalKey<OverlayState> _overlayKey = new LabeledGlobalKey<OverlayState>();
readonly HashSet<Route> _poppedRoutes = new HashSet<Route>();
public readonly FocusScopeNode focusScopeNode = new FocusScopeNode();
readonly HashSet<int> _activePointers = new HashSet<int>();
bool _debugLocked;
readonly List<OverlayEntry> _initialOverlayEntries = new List<OverlayEntry>();
int _userGesturesInProgress;
public OverlayState overlay => this._overlayKey.currentState;
OverlayEntry _currentOverlayEntry {
get {
var route = this._history.FindLast(r => r.overlayEntries.isNotEmpty());
return route?.overlayEntries.last();
}
}
public bool userGestureInProgress => this._userGesturesInProgress > 0;
public override void initState() {
base.initState();
foreach (var observer in this.widget.observers) {
D.assert(observer.navigator == null);
observer._navigator = this;
}
var initialRouteName = this.widget.initialRoute ?? Navigator.defaultRouteName;
if (initialRouteName.StartsWith("/") && initialRouteName.Length > 1) {
initialRouteName = initialRouteName.Substring(1);
D.assert(Navigator.defaultRouteName == "/");
var plannedInitialRouteNames = new List<string> {
Navigator.defaultRouteName
};
var plannedInitialRoutes = new List<Route> {
this._routeNamed(Navigator.defaultRouteName, true)
};
var routeParts = initialRouteName.Split('/');
if (initialRouteName.isNotEmpty()) {
var routeName = "";
foreach (var part in routeParts) {
routeName += $"/{part}";
plannedInitialRouteNames.Add(routeName);
plannedInitialRoutes.Add(this._routeNamed(routeName, true));
}
}
if (plannedInitialRoutes.Contains(null)) {
D.assert(() => {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
new Exception(
"Could not navigate to initial route.\n" +
$"The requested route name was: \"{initialRouteName}\n" +
"The following routes were therefore attempted:\n" +
$" * {string.Join("\n * ", plannedInitialRouteNames)}\n" +
"This resulted in the following objects:\n" +
$" * {string.Join("\n * ", plannedInitialRoutes)}\n" +
"One or more of those objects was null, and therefore the initial route specified will be " +
$"ignored and \"{Navigator.defaultRouteName}\" will be used instead.")));
return true;
});
this.push(this._routeNamed(Navigator.defaultRouteName));
}
else {
plannedInitialRoutes.Each(route => { this.push(route); });
}
}
else {
Route route = null;
if (initialRouteName != Navigator.defaultRouteName) route = this._routeNamed(initialRouteName, true);
route = route ?? this._routeNamed(Navigator.defaultRouteName);
this.push(route);
}
foreach (var route in this._history) this._initialOverlayEntries.AddRange(route.overlayEntries);
}
public override void didUpdateWidget(StatefulWidget oldWidget) {
base.didUpdateWidget(oldWidget);
if (((Navigator) oldWidget).observers != this.widget.observers) {
foreach (var observer in ((Navigator) oldWidget).observers) observer._navigator = null;
foreach (var observer in this.widget.observers) {
D.assert(observer.navigator == null);
observer._navigator = this;
}
}
foreach (var route in this._history) route.changedExternalState();
}
public override void dispose() {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
foreach (var observer in this.widget.observers) observer._navigator = null;
var doomed = this._poppedRoutes.ToList();
doomed.AddRange(this._history);
foreach (var route in doomed) route.dispose();
this._poppedRoutes.Clear();
this._history.Clear();
this.focusScopeNode.detach();
base.dispose();
D.assert(() => {
this._debugLocked = false;
return true;
});
}
Route _routeNamed(string name, bool allowNull = false) {
D.assert(!this._debugLocked);
D.assert(name != null);
var settings = new RouteSettings(name, this._history.isEmpty());
var route = this.widget.onGenerateRoute(settings);
if (route == null && !allowNull) {
D.assert(() => {
if (this.widget.onUnknownRoute == null)
throw new UIWidgetsError(
"If a Navigator has no onUnknownRoute, then its onGenerateRoute must never return null.\n" +
$"When trying to build the route \"{name}\", onGenerateRoute returned null, but there was no " +
"onUnknownRoute callback specified.\n" +
"The Navigator was:\n" +
$" {this}");
return true;
});
route = this.widget.onUnknownRoute(settings);
D.assert(() => {
if (route == null)
throw new UIWidgetsError(
"A Navigator\'s onUnknownRoute returned null.\n" +
$"When trying to build the route \"{name}\", both onGenerateRoute and onUnknownRoute returned " +
"null. The onUnknownRoute callback should never return null.\n" +
"The Navigator was:\n" +
$" {this}"
);
return true;
});
}
return route;
}
public Promise<object> pushNamed(string routeName) {
return this.push(this._routeNamed(routeName));
}
public Promise<object> pushReplacementNamed(string routeName, object result = null) {
return this.pushReplacement(this._routeNamed(routeName), result);
}
public Promise<object> popAndPushNamed(string routeName, object result = null) {
this.pop(result);
return this.pushNamed(routeName);
}
public Promise<object> pushNamedAndRemoveUntil(string newRouteName, RoutePredicate predicate) {
return this.pushAndRemoveUntil(this._routeNamed(newRouteName), predicate);
}
public Promise<object> push(Route route) {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
D.assert(route != null);
D.assert(route._navigator == null);
var oldRoute = this._history.isNotEmpty() ? this._history.last() : null;
route._navigator = this;
route.install(this._currentOverlayEntry);
this._history.Add(route);
route.didPush();
route.didChangeNext(null);
if (oldRoute != null) {
oldRoute.didChangeNext(route);
route.didChangePrevious(oldRoute);
}
foreach (var observer in this.widget.observers) observer.didPush(route, oldRoute);
D.assert(() => {
this._debugLocked = false;
return true;
});
this._afterNavigation();
return route.popped;
}
void _afterNavigation() {
}
public Promise<object> pushReplacement(Route newRoute, object result = null) {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
var oldRoute = this._history.last();
D.assert(oldRoute != null && oldRoute._navigator == this);
D.assert(oldRoute.overlayEntries.isNotEmpty());
D.assert(newRoute._navigator == null);
D.assert(newRoute.overlayEntries.isEmpty());
var index = this._history.Count - 1;
D.assert(index >= 0);
D.assert(this._history.IndexOf(oldRoute) == index);
newRoute._navigator = this;
newRoute.install(this._currentOverlayEntry);
this._history[index] = newRoute;
newRoute.didPush().whenCompleteOrCancel(() => {
// The old route's exit is not animated. We're assuming that the
// new route completely obscures the old one.
if (this.mounted) {
oldRoute.didComplete(result ?? oldRoute.currentResult);
oldRoute.dispose();
}
});
newRoute.didChangeNext(null);
if (index > 0) {
this._history[index - 1].didChangeNext(newRoute);
newRoute.didChangePrevious(this._history[index - 1]);
}
foreach (var observer in this.widget.observers) observer.didReplace(newRoute, oldRoute);
D.assert(() => {
this._debugLocked = false;
return true;
});
this._afterNavigation();
return newRoute.popped;
}
public Promise<object> pushAndRemoveUntil(Route newRoute, RoutePredicate predicate) {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
var removedRoutes = new List<Route>();
while (this._history.isNotEmpty() && !predicate(this._history.last())) {
var removedRoute = this._history.last();
this._history.RemoveAt(this._history.Count - 1);
D.assert(removedRoute != null && removedRoute._navigator == this);
D.assert(removedRoute.overlayEntries.isNotEmpty());
removedRoutes.Add(removedRoute);
}
D.assert(newRoute._navigator == null);
D.assert(newRoute.overlayEntries.isEmpty());
var oldRoute = this._history.isNotEmpty() ? this._history.last() : null;
newRoute._navigator = this;
newRoute.install(this._currentOverlayEntry);
this._history.Add(newRoute);
newRoute.didPush().whenCompleteOrCancel(() => {
if (this.mounted)
foreach (var route in removedRoutes)
route.dispose();
});
newRoute.didChangeNext(null);
if (oldRoute != null) oldRoute.didChangeNext(newRoute);
foreach (var observer in this.widget.observers) {
observer.didPush(newRoute, oldRoute);
foreach (var removedRoute in removedRoutes) observer.didRemove(removedRoute, oldRoute);
}
D.assert(() => {
this._debugLocked = false;
return true;
});
this._afterNavigation();
return newRoute.popped;
}
public void replace(Route oldRoute = null, Route newRoute = null) {
D.assert(!this._debugLocked);
D.assert(oldRoute != null);
D.assert(newRoute != null);
if (oldRoute == newRoute
) // ignore: unrelated_type_equality_checks, https://github.com/dart-lang/sdk/issues/32522
return;
D.assert(() => {
this._debugLocked = true;
return true;
});
D.assert(oldRoute._navigator == this);
D.assert(newRoute._navigator == null);
D.assert(oldRoute.overlayEntries.isNotEmpty());
D.assert(newRoute.overlayEntries.isEmpty());
D.assert(!this.overlay.debugIsVisible(oldRoute.overlayEntries.last()));
var index = this._history.IndexOf(oldRoute);
D.assert(index >= 0);
newRoute._navigator = this;
newRoute.install(oldRoute.overlayEntries.last());
this._history[index] = newRoute;
newRoute.didReplace(oldRoute);
if (index + 1 < this._history.Capacity) {
newRoute.didChangeNext(this._history[index + 1]);
this._history[index + 1].didChangePrevious(newRoute);
}
else {
newRoute.didChangeNext(null);
}
if (index > 0) {
this._history[index - 1].didChangeNext(newRoute);
newRoute.didChangePrevious(this._history[index - 1]);
}
foreach (var observer in this.widget.observers) observer.didReplace(newRoute, oldRoute);
oldRoute.dispose();
D.assert(() => {
this._debugLocked = false;
return true;
});
}
public void replaceRouteBelow(Route anchorRoute = null, Route newRoute = null) {
D.assert(anchorRoute != null);
D.assert(anchorRoute._navigator == this);
D.assert(this._history.IndexOf(anchorRoute) > 0);
this.replace(this._history[this._history.IndexOf(anchorRoute) - 1], newRoute);
}
public bool canPop() {
D.assert(this._history.isNotEmpty);
return this._history.Count > 1 || this._history[0].willHandlePopInternally;
}
public IPromise<bool> maybePop(object result = null) {
var route = this._history.last();
D.assert(route._navigator == this);
return route.willPop().Then(disposition => {
if (disposition != RoutePopDisposition.bubble && this.mounted) {
if (disposition == RoutePopDisposition.pop) this.pop(result);
return Promise<bool>.Resolved(true);
}
return Promise<bool>.Resolved(false);
});
}
public bool pop(object result = null) {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
var route = this._history.last();
D.assert(route._navigator == this);
var debugPredictedWouldPop = false;
D.assert(() => {
debugPredictedWouldPop = !route.willHandlePopInternally;
return true;
});
if (route.didPop(result ?? route.currentResult)) {
D.assert(debugPredictedWouldPop);
if (this._history.Count > 1) {
this._history.removeLast();
// If route._navigator is null, the route called finalizeRoute from
// didPop, which means the route has already been disposed and doesn't
// need to be added to _poppedRoutes for later disposal.
if (route._navigator != null) this._poppedRoutes.Add(route);
this._history.last().didPopNext(route);
foreach (var observer in this.widget.observers) observer.didPop(route, this._history.last());
}
else {
D.assert(() => {
this._debugLocked = false;
return true;
});
return false;
}
}
else {
D.assert(!debugPredictedWouldPop);
}
D.assert(() => {
this._debugLocked = false;
return true;
});
this._afterNavigation();
return true;
}
public void popUntil(RoutePredicate predicate) {
while (!predicate(this._history.last())) this.pop();
}
public void removeRoute(Route route) {
D.assert(route != null);
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
D.assert(route._navigator == this);
var index = this._history.IndexOf(route);
D.assert(index != -1);
var previousRoute = index > 0 ? this._history[index - 1] : null;
var nextRoute = index + 1 < this._history.Count ? this._history[index + 1] : null;
this._history.RemoveAt(index);
previousRoute?.didChangeNext(nextRoute);
nextRoute?.didChangePrevious(previousRoute);
foreach (var observer in this.widget.observers) observer.didRemove(route, previousRoute);
route.dispose();
D.assert(() => {
this._debugLocked = false;
return true;
});
this._afterNavigation();
}
public void removeRouteBelow(Route anchorRoute) {
D.assert(!this._debugLocked);
D.assert(() => {
this._debugLocked = true;
return true;
});
D.assert(anchorRoute._navigator == this);
var index = this._history.IndexOf(anchorRoute) - 1;
D.assert(index >= 0);
var targetRoute = this._history[index];
D.assert(targetRoute._navigator == this);
D.assert(targetRoute.overlayEntries.isEmpty() ||
!this.overlay.debugIsVisible(targetRoute.overlayEntries.last()));
this._history.RemoveAt(index);
var nextRoute = index < this._history.Count ? this._history[index] : null;
var previousRoute = index > 0 ? this._history[index - 1] : null;
if (previousRoute != null)
previousRoute.didChangeNext(nextRoute);
if (nextRoute != null)
nextRoute.didChangePrevious(previousRoute);
targetRoute.dispose();
D.assert(() => {
this._debugLocked = false;
return true;
});
}
public void finalizeRoute(Route route) {
this._poppedRoutes.Remove(route);
route.dispose();
}
public void didStartUserGesture() {
this._userGesturesInProgress += 1;
if (this._userGesturesInProgress == 1) {
var route = this._history.last();
var previousRoute = !route.willHandlePopInternally && this._history.Count > 1
? this._history[this._history.Count - 2]
: null;
// Don't operate the _history list since the gesture may be cancelled.
// In case of a back swipe, the gesture controller will call .pop() itself.
foreach (var observer in this.widget.observers) observer.didStartUserGesture(route, previousRoute);
}
}
public void didStopUserGesture() {
D.assert(this._userGesturesInProgress > 0);
this._userGesturesInProgress -= 1;
if (this._userGesturesInProgress == 0)
foreach (var observer in this.widget.observers)
observer.didStopUserGesture();
}
void _handlePointerDown(PointerDownEvent evt) {
this._activePointers.Add(evt.pointer);
}
void _handlePointerUpOrCancel(PointerEvent evt) {
this._activePointers.Remove(evt.pointer);
}
void _cancelActivePointers() {
// TODO flutter issue https://github.com/flutter/flutter/issues/4770
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) {
// If we're between frames (SchedulerPhase.idle) then absorb any
// subsequent pointers from this frame. The absorbing flag will be
// reset in the next frame, see build().
var absorber = (RenderAbsorbPointer) this._overlayKey.currentContext?
.ancestorRenderObjectOfType(new TypeMatcher<RenderAbsorbPointer>());
this.setState(() => {
if (absorber != null) absorber.absorbing = true;
});
}
foreach (var activePointer in this._activePointers) WidgetsBinding.instance.cancelPointer(activePointer);
}
public override Widget build(BuildContext context) {
D.assert(!this._debugLocked);
D.assert(this._history.isNotEmpty());
return new Listener(
onPointerDown: this._handlePointerDown,
onPointerUp: this._handlePointerUpOrCancel,
onPointerCancel: this._handlePointerUpOrCancel,
child: new AbsorbPointer(
absorbing: false, // it's mutated directly by _cancelActivePointers above
child: new FocusScope(
this.focusScopeNode,
autofocus: true,
child: new Overlay(
this._overlayKey,
this._initialOverlayEntries
)
)
)
);
}
}
}

11
Runtime/widgets/navigator.cs.meta


fileFormatVersion: 2
guid: 78638000dd54446508ed86d5936a4493
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

397
Runtime/widgets/overlay.cs


using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
namespace Unity.UIWidgets.widgets {
public class OverlayEntry {
public OverlayEntry(WidgetBuilder builder = null, bool opaque = false, bool maintainState = false) {
D.assert(builder != null);
this._opaque = opaque;
this._maintainState = maintainState;
this.builder = builder;
}
public readonly WidgetBuilder builder;
bool _opaque;
public bool opaque {
get => this._opaque;
set {
if (this._opaque == value) return;
this._opaque = value;
D.assert(this._overlay != null);
this._overlay._didChangeEntryOpacity();
}
}
bool _maintainState;
public bool maintainState {
get => this._maintainState;
set {
if (this._maintainState == value) return;
this._maintainState = value;
D.assert(this._overlay != null);
this._overlay._didChangeEntryOpacity();
}
}
internal OverlayState _overlay;
internal readonly GlobalKey<_OverlayEntryState> _key = new LabeledGlobalKey<_OverlayEntryState>();
public void remove() {
D.assert(this._overlay != null);
OverlayState overlay = this._overlay;
this._overlay = null;
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks)
SchedulerBinding.instance.addPostFrameCallback((duration) => { overlay._remove(this); });
else
overlay._remove(this);
}
public void markNeedsBuild() {
this._key.currentState?._markNeedsBuild();
}
public override string ToString() {
return $"{Diagnostics.describeIdentity(this)}(opaque: {this.opaque}; maintainState: {this.maintainState})";
}
}
internal class _OverlayEntry : StatefulWidget {
internal _OverlayEntry(OverlayEntry entry) : base(key: entry._key) {
D.assert(entry != null);
this.entry = entry;
}
public readonly OverlayEntry entry;
public override State createState() {
return new _OverlayEntryState();
}
}
internal class _OverlayEntryState : State<_OverlayEntry> {
public override Widget build(BuildContext context) {
return this.widget.entry.builder(context);
}
internal void _markNeedsBuild() {
this.setState(() => {
/* the state that changed is in the builder */
});
}
}
public class Overlay : StatefulWidget {
public Overlay(Key key = null, List<OverlayEntry> initialEntries = null) : base(key) {
D.assert(initialEntries != null);
this.initialEntries = initialEntries;
}
public readonly List<OverlayEntry> initialEntries;
public static OverlayState of(BuildContext context, Widget debugRequiredFor = null) {
OverlayState result = (OverlayState) context.ancestorStateOfType(new TypeMatcher<OverlayState>());
D.assert(() => {
if (debugRequiredFor != null && result == null) {
var additional = context.widget != debugRequiredFor
? $"\nThe context from which that widget was searching for an overlay was:\n {context}"
: "";
throw new UIWidgetsError(
"No Overlay widget found.\n" +
$"{debugRequiredFor.GetType()} widgets require an Overlay widget ancestor for correct operation.\n" +
"The most common way to add an Overlay to an application is to include a MaterialApp or Navigator widget in the runApp() call.\n" +
"The specific widget that failed to find an overlay was:\n" +
$" {debugRequiredFor}" +
$"{additional}"
);
}
return true;
});
return result;
}
public override State createState() {
return new OverlayState();
}
}
public class OverlayState : TickerProviderStateMixin<Overlay> {
readonly List<OverlayEntry> _entries = new List<OverlayEntry>();
public override void initState() {
base.initState();
this.insertAll(this.widget.initialEntries);
}
public void insert(OverlayEntry entry, OverlayEntry above = null) {
D.assert(entry._overlay == null);
D.assert(above == null || (above._overlay == this && this._entries.Contains(above)));
entry._overlay = this;
this.setState(() => {
int index = above == null ? this._entries.Count : this._entries.IndexOf(above) + 1;
this._entries.Insert(index, entry);
});
}
public void insertAll(ICollection<OverlayEntry> entries, OverlayEntry above = null) {
D.assert(above == null || (above._overlay == this && this._entries.Contains(above)));
if (entries.isEmpty())
return;
foreach (OverlayEntry entry in entries) {
D.assert(entry._overlay == null);
entry._overlay = this;
}
this.setState(() => {
int index = above == null ? this._entries.Count : this._entries.IndexOf(above) + 1;
this._entries.InsertRange(index, entries);
});
}
internal void _remove(OverlayEntry entry) {
if (this.mounted) {
this._entries.Remove(entry);
this.setState(() => {
/* entry was removed */
});
}
}
public bool debugIsVisible(OverlayEntry entry) {
bool result = false;
D.assert(this._entries.Contains(entry));
D.assert(() => {
for (int i = this._entries.Count - 1; i > 0; i -= 1) {
// todo why not including 0?
OverlayEntry candidate = this._entries[i];
if (candidate == entry) {
result = true;
break;
}
if (candidate.opaque)
break;
}
return true;
});
return result;
}
internal void _didChangeEntryOpacity() {
this.setState(() => { });
}
public override Widget build(BuildContext context) {
var onstageChildren = new List<Widget>();
var offstageChildren = new List<Widget>();
var onstage = true;
for (var i = this._entries.Count - 1; i >= 0; i -= 1) {
var entry = this._entries[i];
if (onstage) {
onstageChildren.Add(new _OverlayEntry(entry));
if (entry.opaque) onstage = false;
}
else if (entry.maintainState) {
offstageChildren.Add(new TickerMode(enabled: false, child: new _OverlayEntry(entry)));
}
}
onstageChildren.Reverse();
return new _Theatre(
onstage: new Stack(
fit: StackFit.expand,
children: onstageChildren
),
offstage: offstageChildren
);
}
}
internal class _Theatre : RenderObjectWidget {
internal _Theatre(Stack onstage = null, List<Widget> offstage = null) {
D.assert(offstage != null);
D.assert(!offstage.Any((child) => child == null));
this.onstage = onstage;
this.offstage = offstage;
}
public readonly Stack onstage;
public readonly List<Widget> offstage;
public override Element createElement() {
return new _TheatreElement(this);
}
public override RenderObject createRenderObject(BuildContext context) {
return new _RenderTheatre();
}
}
internal class _TheatreElement : RenderObjectElement {
public _TheatreElement(RenderObjectWidget widget) : base(widget) {
D.assert(!WidgetsD.debugChildrenHaveDuplicateKeys(widget, ((_Theatre) widget).offstage));
}
public new _Theatre widget => (_Theatre) base.widget;
public new _RenderTheatre renderObject => (_RenderTheatre) base.renderObject;
Element _onstage;
static readonly object _onstageSlot = new object();
List<Element> _offstage;
readonly HashSet<Element> _forgottenOffstageChildren = new HashSet<Element>();
protected override void insertChildRenderObject(RenderObject child, object slot) {
D.assert(this.renderObject.debugValidateChild(child));
if (slot == _onstageSlot) {
D.assert(child is RenderStack);
this.renderObject.child = (RenderStack) child;
}
else {
D.assert(slot == null || slot is Element);
this.renderObject.insert((RenderBox) child, after: (RenderBox) ((Element) slot)?.renderObject);
}
}
protected override void moveChildRenderObject(RenderObject child, object slot) {
if (slot == _onstageSlot) {
this.renderObject.remove((RenderBox) child);
D.assert(child is RenderStack);
this.renderObject.child = (RenderStack) child;
}
else {
D.assert(slot == null || slot is Element);
if (this.renderObject.child == child) {
this.renderObject.child = null;
this.renderObject.insert((RenderBox) child, after: (RenderBox) ((Element) slot)?.renderObject);
}
else {
this.renderObject.move((RenderBox) child, after: (RenderBox) ((Element) slot)?.renderObject);
}
}
}
protected override void removeChildRenderObject(RenderObject child) {
if (this.renderObject.child == child)
this.renderObject.child = null;
else
this.renderObject.remove((RenderBox) child);
}
public override void visitChildren(ElementVisitor visitor) {
if (this._onstage != null)
visitor(this._onstage);
foreach (var child in this._offstage)
if (!this._forgottenOffstageChildren.Contains(child))
visitor(child);
}
public override void debugVisitOnstageChildren(ElementVisitor visitor) {
if (this._onstage != null)
visitor(this._onstage);
}
protected override void forgetChild(Element child) {
if (child == this._onstage) {
this._onstage = null;
}
else {
D.assert(this._offstage.Contains(child));
D.assert(!this._forgottenOffstageChildren.Contains(child));
this._forgottenOffstageChildren.Add(child);
}
}
public override void mount(Element parent, object newSlot) {
base.mount(parent, newSlot);
this._onstage = this.updateChild(this._onstage, this.widget.onstage, _onstageSlot);
this._offstage = new List<Element>(this.widget.offstage.Count);
Element previousChild = null;
for (int i = 0; i < this._offstage.Count; i += 1) {
var newChild = this.inflateWidget(this.widget.offstage[i], previousChild);
this._offstage[i] = newChild;
previousChild = newChild;
}
}
public override void update(Widget newWidget) {
base.update(newWidget);
D.assert(Equals(this.widget, newWidget));
this._onstage = this.updateChild(this._onstage, this.widget.onstage, _onstageSlot);
this._offstage = this.updateChildren(this._offstage, this.widget.offstage,
forgottenChildren: this._forgottenOffstageChildren);
this._forgottenOffstageChildren.Clear();
}
}
internal class _RenderTheatre :
ContainerRenderObjectMixinRenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack<
RenderBox, StackParentData> {
public override void setupParentData(RenderObject child) {
if (!(child.parentData is StackParentData))
child.parentData = new StackParentData();
}
public override void redepthChildren() {
if (this.child != null) this.redepthChild(this.child);
base.redepthChildren();
}
public override void visitChildren(RenderObjectVisitor visitor) {
if (this.child != null)
visitor(this.child);
base.visitChildren(visitor);
}
public override List<DiagnosticsNode> debugDescribeChildren() {
var children = new List<DiagnosticsNode>();
if (this.child != null)
children.Add(this.child.toDiagnosticsNode(name: "onstage"));
if (this.firstChild != null) {
var child = this.firstChild;
int count = 1;
while (true) {
children.Add(
child.toDiagnosticsNode(
name: $"offstage {count}",
style: DiagnosticsTreeStyle.offstage
)
);
if (child == this.lastChild)
break;
var childParentData = (StackParentData) child.parentData;
child = childParentData.nextSibling;
count += 1;
}
}
else {
children.Add(
DiagnosticsNode.message(
"no offstage children",
style: DiagnosticsTreeStyle.offstage
)
);
}
return children;
}
}
}

11
Runtime/widgets/overlay.cs.meta


fileFormatVersion: 2
guid: b92d0bc4e5fb643c1beee12417aec777
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

88
Runtime/widgets/pages.cs


using System;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public abstract class PageRoute : ModalRoute {
public readonly bool fullscreenDialog;
public PageRoute(RouteSettings settings, bool fullscreenDialog = false) : base(settings) {
this.fullscreenDialog = fullscreenDialog;
}
public override bool opaque => false;
public override bool barrierDismissible => false;
public override bool canTransitionTo(TransitionRoute nextRoute) {
return nextRoute is PageRoute;
}
public override bool canTransitionFrom(TransitionRoute previousRoute) {
return previousRoute is PageRoute;
}
public override AnimationController createAnimationController() {
var controller = base.createAnimationController();
if (this.settings.isInitialRoute)
controller.setValue(1.0);
return controller;
}
}
public class PageRouteBuilder : PageRoute {
public readonly RoutePageBuilder pageBuilder;
public readonly RouteTransitionsBuilder transitionsBuilder;
public PageRouteBuilder(
RouteSettings settings = null,
RoutePageBuilder pageBuilder = null,
RouteTransitionsBuilder transitionsBuilder = null,
TimeSpan? transitionDuration = null,
bool opaque = true,
bool barrierDismissible = false,
Color barrierColor = null,
string barrierLabel = null,
bool maintainState = true
) : base(settings) {
D.assert(pageBuilder != null);
this.opaque = opaque;
this.pageBuilder = pageBuilder;
this.transitionsBuilder = transitionsBuilder ?? this._defaultTransitionsBuilder;
this.transitionDuration = transitionDuration ?? TimeSpan.FromMilliseconds(300);
this.barrierColor = barrierColor;
this.maintainState = maintainState;
this.barrierLabel = barrierLabel;
this.barrierDismissible = barrierDismissible;
}
public override TimeSpan transitionDuration { get; }
public override bool opaque { get; }
public override bool barrierDismissible { get; }
public override Color barrierColor { get; }
public override string barrierLabel { get; }
public override bool maintainState { get; }
Widget _defaultTransitionsBuilder(BuildContext context, Animation<double>
animation, Animation<double> secondaryAnimation, Widget child) {
return child;
}
public override Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return this.pageBuilder(context, animation, secondaryAnimation);
}
public override Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return this.transitionsBuilder(context, animation, secondaryAnimation, child);
}
}
}

11
Runtime/widgets/pages.cs.meta


fileFormatVersion: 2
guid: b42abffbabbf94d6c92274cfbc74eec0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

773
Runtime/widgets/routes.cs


using System;
using System.Collections.Generic;
using RSG;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public abstract class OverlayRoute : Route {
readonly List<OverlayEntry> _overlayEntries = new List<OverlayEntry>();
public OverlayRoute(
RouteSettings settings = null
) : base(settings) {
}
public override List<OverlayEntry> overlayEntries => this._overlayEntries;
protected virtual bool finishedWhenPopped => true;
public abstract ICollection<OverlayEntry> createOverlayEntries();
protected internal override void install(OverlayEntry insertionPoint) {
D.assert(this._overlayEntries.isEmpty());
this._overlayEntries.AddRange(this.createOverlayEntries());
this.navigator.overlay?.insertAll(this._overlayEntries, insertionPoint);
base.install(insertionPoint);
}
protected internal override bool didPop(object result) {
var returnValue = base.didPop(result);
D.assert(returnValue);
if (this.finishedWhenPopped) this.navigator.finalizeRoute(this);
return returnValue;
}
protected internal override void dispose() {
foreach (var entry in this._overlayEntries) entry.remove();
this._overlayEntries.Clear();
base.dispose();
}
}
public abstract class TransitionRoute : OverlayRoute {
public TransitionRoute(
RouteSettings settings = null
) : base(settings) {
}
public IPromise<object> completed => this._transitionCompleter;
internal readonly Promise<object> _transitionCompleter = new Promise<object>();
public virtual TimeSpan transitionDuration { get; }
public virtual bool opaque { get; }
protected override bool finishedWhenPopped => this.controller.status == AnimationStatus.dismissed;
public virtual Animation<double> animation => this._animation;
internal Animation<double> _animation;
public AnimationController controller => this._controller;
internal AnimationController _controller;
public virtual AnimationController createAnimationController() {
D.assert(this._transitionCompleter.CurState == PromiseState.Pending,
$"Cannot reuse a {this.GetType()} after disposing it.");
TimeSpan duration = this.transitionDuration;
D.assert(duration >= TimeSpan.Zero);
return new AnimationController(
duration: duration,
debugLabel: this.debugLabel,
vsync: this.navigator
);
}
public virtual Animation<double> createAnimation() {
D.assert(this._transitionCompleter.CurState == PromiseState.Pending,
$"Cannot reuse a {this.GetType()} after disposing it.");
D.assert(this._controller != null);
return this._controller.view;
}
object _result;
internal void _handleStatusChanged(AnimationStatus status) {
switch (status) {
case AnimationStatus.completed:
if (this.overlayEntries.isNotEmpty())
this.overlayEntries.first().opaque = this.opaque;
break;
case AnimationStatus.forward:
case AnimationStatus.reverse:
if (this.overlayEntries.isNotEmpty())
this.overlayEntries.first().opaque = false;
break;
case AnimationStatus.dismissed:
D.assert(!this.overlayEntries.first().opaque);
// We might still be the current route if a subclass is controlling the
// the transition and hits the dismissed status. For example, the iOS
// back gesture drives this animation to the dismissed status before
// popping the navigator.
if (!this.isCurrent) {
this.navigator.finalizeRoute(this);
D.assert(this.overlayEntries.isEmpty());
}
break;
}
this.changedInternalState();
}
public virtual Animation<double> secondaryAnimation => this._secondaryAnimation;
readonly ProxyAnimation _secondaryAnimation = new ProxyAnimation(Animations.kAlwaysDismissedAnimation);
protected internal override void install(OverlayEntry insertionPoint) {
D.assert(!this._transitionCompleter.isCompleted, $"Cannot install a {this.GetType()} after disposing it.");
this._controller = this.createAnimationController();
D.assert(this._controller != null, $"{this.GetType()}.createAnimationController() returned null.");
this._animation = this.createAnimation();
D.assert(this._animation != null, $"{this.GetType()}.createAnimation() returned null.");
base.install(insertionPoint);
}
protected internal override TickerFuture didPush() {
D.assert(this._controller != null,
$"{this.GetType()}.didPush called before calling install() or after calling dispose().");
D.assert(!this._transitionCompleter.isCompleted, $"Cannot reuse a {this.GetType()} after disposing it.");
this._animation.addStatusListener(this._handleStatusChanged);
return this._controller.forward();
}
protected internal override void didReplace(Route oldRoute) {
D.assert(this._controller != null,
$"{this.GetType()}.didReplace called before calling install() or after calling dispose().");
D.assert(!this._transitionCompleter.isCompleted, $"Cannot reuse a {this.GetType()} after disposing it.");
if (oldRoute is TransitionRoute route)
this._controller.setValue(route._controller.value);
this._animation.addStatusListener(this._handleStatusChanged);
base.didReplace(oldRoute);
}
protected internal override bool didPop(object result) {
D.assert(this._controller != null,
$"{this.GetType()}.didPop called before calling install() or after calling dispose().");
D.assert(!this._transitionCompleter.isCompleted, $"Cannot reuse a {this.GetType()} after disposing it.");
this._result = result;
this._controller.reverse();
return base.didPop(result);
}
protected internal override void didPopNext(Route nextRoute) {
D.assert(this._controller != null,
$"{this.GetType()}.didPopNext called before calling install() or after calling dispose().");
D.assert(!this._transitionCompleter.isCompleted, $"Cannot reuse a {this.GetType()} after disposing it.");
this._updateSecondaryAnimation(nextRoute);
base.didPopNext(nextRoute);
}
protected internal override void didChangeNext(Route nextRoute) {
D.assert(this._controller != null,
$"{this.GetType()}.didChangeNext called before calling install() or after calling dispose().");
D.assert(!this._transitionCompleter.isCompleted, $"Cannot reuse a {this.GetType()} after disposing it.");
this._updateSecondaryAnimation(nextRoute);
base.didChangeNext(nextRoute);
}
void _updateSecondaryAnimation(Route nextRoute) {
if (nextRoute is TransitionRoute && this.canTransitionTo((TransitionRoute) nextRoute) &&
((TransitionRoute) nextRoute).canTransitionFrom(this)) {
Animation<double> current = this._secondaryAnimation.parent;
if (current != null) {
if (current is TrainHoppingAnimation) {
TrainHoppingAnimation newAnimation = null;
newAnimation = new TrainHoppingAnimation(
((TrainHoppingAnimation) current).currentTrain,
((TransitionRoute) nextRoute)._animation,
onSwitchedTrain: () => {
D.assert(this._secondaryAnimation.parent == newAnimation);
D.assert(newAnimation.currentTrain == ((TransitionRoute) nextRoute)._animation);
this._secondaryAnimation.parent = newAnimation.currentTrain;
newAnimation.dispose();
}
);
this._secondaryAnimation.parent = newAnimation;
((TrainHoppingAnimation) current).dispose();
}
else {
this._secondaryAnimation.parent =
new TrainHoppingAnimation(current, ((TransitionRoute) nextRoute)._animation);
}
}
else {
this._secondaryAnimation.parent = ((TransitionRoute) nextRoute)._animation;
}
}
else {
this._secondaryAnimation.parent = Animations.kAlwaysDismissedAnimation;
}
}
public virtual bool canTransitionTo(TransitionRoute nextRoute) {
return true;
}
public virtual bool canTransitionFrom(TransitionRoute previousRoute) {
return true;
}
protected internal override void dispose() {
D.assert(!this._transitionCompleter.isCompleted, $"Cannot dispose a {this.GetType()} twice.");
this._controller?.dispose();
this._transitionCompleter.Resolve(this._result);
base.dispose();
}
public string debugLabel => $"{this.GetType()}";
public override string ToString() {
return $"{this.GetType()}(animation: {this._controller}";
}
}
public class LocalHistoryEntry {
public LocalHistoryEntry(VoidCallback onRemove = null) {
this.onRemove = onRemove;
}
public readonly VoidCallback onRemove;
internal LocalHistoryRoute _owner;
public void remove() {
this._owner.removeLocalHistoryEntry(this);
D.assert(this._owner == null);
}
internal void _notifyRemoved() {
this.onRemove?.Invoke();
}
}
public interface LocalHistoryRoute {
void addLocalHistoryEntry(LocalHistoryEntry entry);
void removeLocalHistoryEntry(LocalHistoryEntry entry);
Route route { get; }
}
// todo make it to mixin
public abstract class LocalHistoryRouteTransitionRoute : TransitionRoute, LocalHistoryRoute {
List<LocalHistoryEntry> _localHistory;
protected LocalHistoryRouteTransitionRoute(RouteSettings settings = null) : base(settings: settings) {
}
public void addLocalHistoryEntry(LocalHistoryEntry entry) {
D.assert(entry._owner == null);
entry._owner = this;
this._localHistory = this._localHistory ?? new List<LocalHistoryEntry>();
var wasEmpty = this._localHistory.isEmpty();
this._localHistory.Add(entry);
if (wasEmpty)
this.changedInternalState();
}
public void removeLocalHistoryEntry(LocalHistoryEntry entry) {
D.assert(entry != null);
D.assert(entry._owner == this);
D.assert(this._localHistory.Contains(entry));
this._localHistory.Remove(entry);
entry._owner = null;
entry._notifyRemoved();
if (this._localHistory.isEmpty()) this.changedInternalState();
}
public override IPromise<RoutePopDisposition> willPop() {
if (this.willHandlePopInternally)
return Promise<RoutePopDisposition>.Resolved(RoutePopDisposition.pop);
return base.willPop();
}
protected internal override bool didPop(object result) {
if (this._localHistory != null && this._localHistory.isNotEmpty()) {
var entry = this._localHistory.removeLast();
D.assert(entry._owner == this);
entry._owner = null;
entry._notifyRemoved();
if (this._localHistory.isEmpty())
this.changedInternalState();
return false;
}
return base.didPop(result);
}
public override bool willHandlePopInternally => this._localHistory != null && this._localHistory.isNotEmpty();
public Route route => this;
}
public class _ModalScopeStatus : InheritedWidget {
public _ModalScopeStatus(Key key = null, bool isCurrent = false,
bool canPop = false, Route route = null, Widget child = null) : base(key: key, child: child) {
D.assert(route != null);
D.assert(child != null);
this.isCurrent = isCurrent;
this.canPop = canPop;
this.route = route;
}
public readonly bool isCurrent;
public readonly bool canPop;
public readonly Route route;
public override bool updateShouldNotify(InheritedWidget oldWidget) {
return this.isCurrent != ((_ModalScopeStatus) oldWidget).isCurrent ||
this.canPop != ((_ModalScopeStatus) oldWidget).canPop ||
this.route != ((_ModalScopeStatus) oldWidget).route;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder description) {
base.debugFillProperties(description);
description.add(new FlagProperty("isCurrent", value: this.isCurrent, ifTrue: "active",
ifFalse: "inactive"));
description.add(new FlagProperty("canPop", value: this.canPop, ifTrue: "can pop"));
}
}
public class _ModalScope : StatefulWidget {
public _ModalScope(Key key = null, ModalRoute route = null) : base(key) {
this.route = route;
}
public readonly ModalRoute route;
public override State createState() {
return new _ModalScopeState();
}
}
public class _ModalScopeState : State<_ModalScope> {
Widget _page;
Listenable _listenable;
public override void initState() {
base.initState();
var animations = new List<Listenable> { };
if (this.widget.route.animation != null)
animations.Add(this.widget.route.animation);
if (this.widget.route.secondaryAnimation != null)
animations.Add(this.widget.route.secondaryAnimation);
this._listenable = ListenableUtils.merge(animations);
}
public override void didUpdateWidget(StatefulWidget oldWidget) {
base.didUpdateWidget(oldWidget);
D.assert(this.widget.route == ((_ModalScope) oldWidget).route);
}
public override void didChangeDependencies() {
base.didChangeDependencies();
this._page = null;
}
internal void _forceRebuildPage() {
this.setState(() => { this._page = null; });
}
internal void _routeSetState(VoidCallback fn) {
this.setState(fn);
}
public override Widget build(BuildContext context) {
this._page = this._page ?? new RepaintBoundary(
key: this.widget.route._subtreeKey, // immutable
child: new Builder(
builder: (BuildContext _context) => this.widget.route.buildPage(
_context,
this.widget.route.animation,
this.widget.route.secondaryAnimation
))
);
return new _ModalScopeStatus(
route: this.widget.route,
isCurrent: this.widget.route.isCurrent,
canPop: this.widget.route.canPop,
child: new Offstage(
offstage: this.widget.route.offstage,
child: new PageStorage(
bucket: this.widget.route._storageBucket,
child: new FocusScope(
node: this.widget.route.focusScopeNode,
child: new RepaintBoundary(
child: new AnimatedBuilder(
animation: this._listenable, // immutable
builder: (BuildContext _context, Widget child) =>
this.widget.route.buildTransitions(
_context,
this.widget.route.animation,
this.widget.route.secondaryAnimation,
new IgnorePointer(
ignoring: this.widget.route.animation?.status ==
AnimationStatus.reverse,
child: child
)
),
child: this._page
)
)
)
)
)
);
}
}
public abstract class ModalRoute : LocalHistoryRouteTransitionRoute {
protected ModalRoute(RouteSettings settings) : base(settings) {
}
public static Color _kTransparent = new Color(0x00000000);
public static ModalRoute of(BuildContext context) {
_ModalScopeStatus widget =
(_ModalScopeStatus) context.inheritFromWidgetOfExactType(typeof(_ModalScopeStatus));
return (ModalRoute) widget?.route;
}
protected virtual void setState(VoidCallback fn) {
if (this._scopeKey.currentState != null)
this._scopeKey.currentState._routeSetState(fn);
else
fn();
}
public RoutePredicate withName(string name) {
return (Route route) => !route.willHandlePopInternally
&& route is ModalRoute
&& route.settings.name == name;
}
public abstract Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation);
public virtual Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child
) {
return child;
}
public readonly FocusScopeNode focusScopeNode = new FocusScopeNode();
protected internal override void install(OverlayEntry insertionPoint) {
base.install(insertionPoint);
this._animationProxy = new ProxyAnimation(base.animation);
this._secondaryAnimationProxy = new ProxyAnimation(base.secondaryAnimation);
}
protected internal override TickerFuture didPush() {
this.navigator.focusScopeNode.setFirstFocus(this.focusScopeNode);
return base.didPush();
}
protected internal override void dispose() {
this.focusScopeNode.detach();
base.dispose();
}
public virtual bool barrierDismissible { get; }
public virtual Color barrierColor { get; }
public virtual string barrierLabel { get; }
public virtual bool maintainState { get; }
public bool offstage {
get => this._offstage;
set {
if (this._offstage == value)
return;
this.setState(() => { this._offstage = value; });
this._animationProxy.parent = this._offstage ? Animations.kAlwaysCompleteAnimation : base.animation;
this._secondaryAnimationProxy.parent =
this._offstage ? Animations.kAlwaysDismissedAnimation : base.secondaryAnimation;
}
}
bool _offstage = false;
public BuildContext subtreeContext => this._subtreeKey.currentContext;
public override Animation<double> animation => this._animationProxy;
ProxyAnimation _animationProxy;
public override Animation<double> secondaryAnimation => this._secondaryAnimationProxy;
ProxyAnimation _secondaryAnimationProxy;
readonly List<WillPopCallback> _willPopCallbacks = new List<WillPopCallback>();
public override IPromise<RoutePopDisposition> willPop() {
_ModalScopeState scope = this._scopeKey.currentState;
D.assert(scope != null);
var callbacks = new List<WillPopCallback>(this._willPopCallbacks);
Promise<RoutePopDisposition> result = new Promise<RoutePopDisposition>();
Action<int> fn = null;
fn = (int index) => {
if (index < callbacks.Count)
callbacks[index]().Then((pop) => {
if (!pop)
result.Resolve(RoutePopDisposition.doNotPop);
else
fn(index + 1);
});
else
base.willPop().Then((pop) => result.Resolve(pop));
};
fn(0);
return result;
}
public void addScopedWillPopCallback(WillPopCallback callback) {
D.assert(this._scopeKey.currentState != null,
"Tried to add a willPop callback to a route that is not currently in the tree.");
this._willPopCallbacks.Add(callback);
}
public void removeScopedWillPopCallback(WillPopCallback callback) {
D.assert(this._scopeKey.currentState != null,
"Tried to remove a willPop callback from a route that is not currently in the tree.");
this._willPopCallbacks.Remove(callback);
}
protected bool hasScopedWillPopCallback => this._willPopCallbacks.isNotEmpty();
protected internal override void didChangePrevious(Route previousRoute) {
base.didChangePrevious(previousRoute);
this.changedInternalState();
}
protected internal override void changedInternalState() {
base.changedInternalState();
this.setState(() => { });
this._modalBarrier.markNeedsBuild();
}
protected internal override void changedExternalState() {
base.changedExternalState();
this._scopeKey.currentState?._forceRebuildPage();
}
public bool canPop => !this.isFirst || this.willHandlePopInternally;
readonly GlobalKey<_ModalScopeState> _scopeKey = new LabeledGlobalKey<_ModalScopeState>();
internal readonly GlobalKey _subtreeKey = new LabeledGlobalKey<_ModalScopeState>();
internal readonly PageStorageBucket _storageBucket = new PageStorageBucket();
static readonly Animatable<double> _easeCurveTween = new CurveTween(curve: Curves.ease);
OverlayEntry _modalBarrier;
Widget _buildModalBarrier(BuildContext context) {
Widget barrier;
if (this.barrierColor != null && !this.offstage) {
// changedInternalState is called if these update
D.assert(this.barrierColor != _kTransparent);
Animation<Color> color =
new ColorTween(
begin: _kTransparent,
end: this.barrierColor // changedInternalState is called if this updates
).chain(_easeCurveTween).animate(this.animation);
barrier = new AnimatedModalBarrier(
color: color,
dismissible: this.barrierDismissible
);
}
else {
barrier = new ModalBarrier(
dismissible: this.barrierDismissible
);
}
return new IgnorePointer(
ignoring: this.animation.status == AnimationStatus.reverse ||
this.animation.status == AnimationStatus.dismissed,
child: barrier
);
}
Widget _modalScopeCache;
Widget _buildModalScope(BuildContext context) {
return this._modalScopeCache = this._modalScopeCache ?? new _ModalScope(
key: this._scopeKey,
route: this
// _ModalScope calls buildTransitions() and buildChild(), defined above
);
}
public override ICollection<OverlayEntry> createOverlayEntries() {
this._modalBarrier = new OverlayEntry(builder: this._buildModalBarrier);
var content = new OverlayEntry(
builder: this._buildModalScope, maintainState: this.maintainState
);
return new List<OverlayEntry> {this._modalBarrier, content};
}
public override string ToString() {
return $"{this.GetType()}({this.settings}, animation: {this._animation})";
}
}
internal abstract class PopupRoute : ModalRoute {
protected PopupRoute(
RouteSettings settings = null
) : base(settings: settings) {
}
public override bool opaque => false;
public override bool maintainState => true;
}
public class RouteObserve<R> : NavigatorObserver where R : Route {
readonly Dictionary<R, HashSet<RouteAware>> _listeners = new Dictionary<R, HashSet<RouteAware>>();
public void subscribe(RouteAware routeAware, R route) {
D.assert(routeAware != null);
D.assert(route != null);
HashSet<RouteAware> subscribers = this._listeners.putIfAbsent(route, () => new HashSet<RouteAware>());
if (subscribers.Add(routeAware)) routeAware.didPush();
}
public void unsubscribe(RouteAware routeAware) {
D.assert(routeAware != null);
foreach (R route in this._listeners.Keys) {
HashSet<RouteAware> subscribers = this._listeners[route];
subscribers?.Remove(routeAware);
}
}
public override void didPop(Route route, Route previousRoute) {
if (route is R && previousRoute is R) {
var previousSubscribers = this._listeners.getOrDefault((R) previousRoute);
if (previousSubscribers != null)
foreach (RouteAware routeAware in previousSubscribers)
routeAware.didPopNext();
var subscribers = this._listeners.getOrDefault((R) route);
if (subscribers != null)
foreach (RouteAware routeAware in subscribers)
routeAware.didPop();
}
}
public override void didPush(Route route, Route previousRoute) {
if (route is R && previousRoute is R) {
var previousSubscribers = this._listeners.getOrDefault((R) previousRoute);
if (previousSubscribers != null)
foreach (RouteAware routeAware in previousSubscribers)
routeAware.didPushNext();
}
}
}
public interface RouteAware {
void didPopNext();
void didPush();
void didPop();
void didPushNext();
}
internal class _DialogRoute : PopupRoute {
internal _DialogRoute(RoutePageBuilder pageBuilder = null, bool barrierDismissible = true,
string barrierLabel = null,
Color barrierColor = null,
TimeSpan? transitionDuration = null,
RouteTransitionsBuilder transitionBuilder = null,
RouteSettings setting = null) : base(settings: setting) {
this._pageBuilder = pageBuilder;
this.barrierDismissible = barrierDismissible;
this.barrierLabel = barrierLabel;
this.barrierColor = barrierColor ?? new Color(0x80000000);
this.transitionDuration = transitionDuration ?? TimeSpan.FromMilliseconds(200);
this._transitionBuilder = transitionBuilder;
}
readonly RoutePageBuilder _pageBuilder;
public override bool barrierDismissible { get; }
public override string barrierLabel { get; }
public override Color barrierColor { get; }
public override TimeSpan transitionDuration { get; }
readonly RouteTransitionsBuilder _transitionBuilder;
public override Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return this._pageBuilder(context, animation, secondaryAnimation);
}
public override Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (this._transitionBuilder == null)
return new FadeTransition(
opacity: new CurvedAnimation(
parent: animation,
curve: Curves.linear
),
child: child);
return this._transitionBuilder(context, animation, secondaryAnimation, child);
}
}
public static class DialogUtils {
public static Promise<object> showGeneralDialog(
BuildContext context = null,
RoutePageBuilder pageBuilder = null,
bool barrierDismissible = false,
string barrierLabel = null,
Color barrierColor = null,
TimeSpan? transitionDuration = null,
RouteTransitionsBuilder transitionBuilder = null
) {
D.assert(pageBuilder != null);
D.assert(!barrierDismissible || barrierLabel != null);
return Navigator.of(context, rootNavigator: true).push(new _DialogRoute(
pageBuilder: pageBuilder,
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
barrierColor: barrierColor,
transitionDuration: transitionDuration,
transitionBuilder: transitionBuilder
));
}
}
public delegate Widget RoutePageBuilder(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation);
public delegate Widget RouteTransitionsBuilder(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child);
}

11
Runtime/widgets/routes.cs.meta


fileFormatVersion: 2
guid: 3b5bef8a47dcb49babf3a770d5a3420d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

131
Runtime/widgets/transitions.cs


using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
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<Listenable>("animation", this.listenable));
}
}
public class _AnimatedState : State<AnimatedWidget> {
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<Offset> 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<Offset> position => (Animation<Offset>) 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 FadeTransition : SingleChildRenderObjectWidget {
public FadeTransition(Key key = null, Animation<double> opacity = null,
Widget child = null) : base(key: key, child: child) {
this.opacity = opacity;
}
public readonly Animation<double> 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<Animation<double>>("opacity", this.opacity));
}
}
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);
this.builder = builder;
this.child = child;
}
protected internal override Widget build(BuildContext context) {
return this.builder(context, this.child);
}
}
}

11
Runtime/widgets/transitions.cs.meta


fileFormatVersion: 2
guid: 3df6a337dc40c448881ec2d0454362f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

502
Samples/UIWidgetSample/Navigation.unity


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.44657892, g: 0.4964127, b: 0.5748172, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 1
m_LightmapEditorSettings:
serializedVersion: 10
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringMode: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ShowResolutionOverlay: 1
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &4286172
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4286176}
- component: {fileID: 4286175}
- component: {fileID: 4286174}
- component: {fileID: 4286173}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &4286173
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1301386320, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &4286174
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
--- !u!223 &4286175
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286172}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!224 &4286176
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286172}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
- {fileID: 927824195}
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1 &26611619
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 26611622}
- component: {fileID: 26611621}
- component: {fileID: 26611620}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &26611620
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26611619}
m_Enabled: 1
--- !u!20 &26611621
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26611619}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_GateFitMode: 2
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &26611622
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26611619}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &897547349
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 897547351}
- component: {fileID: 897547350}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &897547350
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 897547349}
m_Enabled: 1
serializedVersion: 8
m_Type: 1
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &897547351
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 897547349}
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &927824194
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 927824195}
- component: {fileID: 927824197}
- component: {fileID: 927824196}
m_Layer: 5
m_Name: Navigation
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &927824195
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927824194}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 4286176}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &927824196
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927824194}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 020016dfbbaef41b496f4e5be17d098c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Texture: {fileID: 0}
m_UVRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
--- !u!222 &927824197
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927824194}
m_CullTransparentMesh: 0
--- !u!1 &1838283857
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1838283860}
- component: {fileID: 1838283859}
- component: {fileID: 1838283858}
m_Layer: 0
m_Name: EventSystem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1838283858
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1838283857}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical
m_SubmitButton: Submit
m_CancelButton: Cancel
m_InputActionsPerSecond: 10
m_RepeatDelay: 0.5
m_ForceModuleActive: 0
--- !u!114 &1838283859
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1838283857}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_FirstSelected: {fileID: 0}
m_sendNavigationEvents: 1
m_DragThreshold: 10
--- !u!4 &1838283860
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1838283857}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

7
Samples/UIWidgetSample/Navigation.unity.meta


fileFormatVersion: 2
guid: 48300882e985d484880e16569661a93c
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

144
Samples/UIWidgetSample/NavigationCanvas.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using Color = Unity.UIWidgets.ui.Color;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace UIWidgetsSample {
public class NavigationCanvas : WidgetCanvas {
protected override string initialRoute => "/";
protected override Dictionary<string, WidgetBuilder> routes => new Dictionary<string, WidgetBuilder> {
{"/", (context) => new HomeScreen()},
{"/detail", (context) => new DetailScreen()}
};
protected override TextStyle textStyle => new TextStyle(fontSize: 24);
protected override PageRouteFactory pageRouteBuilder => (RouteSettings settings, WidgetBuilder builder) =>
new PageRouteBuilder(
settings: settings,
pageBuilder: (BuildContext context, Unity.UIWidgets.animation.Animation<double> animation,
Unity.UIWidgets.animation.Animation<double> secondaryAnimation) => builder(context),
transitionsBuilder: (BuildContext context, Animation<double>
animation, Animation<double> secondaryAnimation, Widget child) => new _FadeUpwardsPageTransition(
routeAnimation: animation,
child: child
)
);
}
class HomeScreen : StatelessWidget {
public override Widget build(BuildContext context) {
return new Container(
color: new Color(0xFF888888),
child: new Center(child: new CustomButton(onPressed: () => {
Navigator.pushName(context, "/detail");
}, child: new Text("Go to Detail"))
));
}
}
class DetailScreen : StatelessWidget {
public override Widget build(BuildContext context) {
return new Container(
color: new Color(0xFF1389FD),
child: new Center(
child: new Column(
children: new List<Widget>() {
new CustomButton(onPressed: () => {
Navigator.pop(context);
}, child: new Text("Back")),
new CustomButton(onPressed: () => {
_Dialog.showDialog(context, builder: (BuildContext c) => new Dialog());
}, child: new Text("Show Dialog"))
}
)
));
}
}
class Dialog : StatelessWidget {
public override Widget build(BuildContext context) {
return new Center(child:new Container(
color: new Color(0xFFFF0000),
width: 100,
height: 80,
child: new Center(
child: new Text("Hello Dialog")
)));
}
}
class _FadeUpwardsPageTransition : StatelessWidget {
internal _FadeUpwardsPageTransition(
Key key = null,
Animation<double> routeAnimation = null, // The route's linear 0.0 - 1.0 animation.
Widget child = null
) :base(key: key) {
this._positionAnimation = _bottomUpTween.chain(_fastOutSlowInTween).animate(routeAnimation);
this._opacityAnimation = _easeInTween.animate(routeAnimation);
this.child = child;
}
static Tween<Offset> _bottomUpTween = new OffsetTween(
begin: new Offset(0.0, 0.25),
end: Offset.zero
);
static Animatable<double> _fastOutSlowInTween = new CurveTween(curve: Curves.fastOutSlowIn);
static Animatable<double> _easeInTween = new CurveTween(curve: Curves.easeIn);
readonly Animation<Offset> _positionAnimation;
readonly Animation<double> _opacityAnimation;
public readonly Widget child;
public override Widget build(BuildContext context) {
return new SlideTransition(
position: this._positionAnimation,
child: new FadeTransition(
opacity: this._opacityAnimation,
child: this.child
)
);
}
}
static class _Dialog {
public static void showDialog(BuildContext context,
bool barrierDismissible = true, WidgetBuilder builder = null) {
DialogUtils.showGeneralDialog(
context: context,
pageBuilder: (BuildContext buildContext, Animation<double> animation,
Animation<double> secondaryAnimation) => {
return builder(buildContext);
},
barrierDismissible: barrierDismissible,
barrierLabel: "",
barrierColor: new Color(0x8A000000),
transitionDuration: TimeSpan.FromMilliseconds(150),
transitionBuilder: _buildMaterialDialogTransitions
);
}
static Widget _buildMaterialDialogTransitions(BuildContext context,
Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return new FadeTransition(
opacity: new CurvedAnimation(
parent: animation,
curve: Curves.easeOut
),
child: child
);
}
}
}

11
Samples/UIWidgetSample/NavigationCanvas.cs.meta


fileFormatVersion: 2
guid: 020016dfbbaef41b496f4e5be17d098c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存