gewentao
6 年前
当前提交
4fd35765
共有 70 个文件被更改,包括 4224 次插入 和 453 次删除
-
14Assets/UIWidgets/Tests/Gestures.cs
-
8Assets/UIWidgets/Tests/Paragraph.cs
-
12Assets/UIWidgets/Tests/RenderBoxes.cs
-
20Assets/UIWidgets/Tests/RenderEditable.cs
-
8Assets/UIWidgets/Tests/Widgets.cs
-
85Assets/UIWidgets/editor/editor_window.cs
-
4Assets/UIWidgets/foundation/assertions.cs
-
2Assets/UIWidgets/foundation/change_notifier.cs
-
10Assets/UIWidgets/foundation/debug.cs
-
139Assets/UIWidgets/foundation/diagnostics.cs
-
7Assets/UIWidgets/gestures/arena.cs
-
15Assets/UIWidgets/gestures/binding.cs
-
2Assets/UIWidgets/gestures/constants.cs
-
9Assets/UIWidgets/gestures/converter.cs
-
16Assets/UIWidgets/gestures/monodrag.cs
-
21Assets/UIWidgets/gestures/multitap.cs
-
21Assets/UIWidgets/gestures/recognizer.cs
-
4Assets/UIWidgets/gestures/tap.cs
-
23Assets/UIWidgets/painting/basic_types.cs
-
8Assets/UIWidgets/physics/utils.cs
-
9Assets/UIWidgets/promise/Promise.cs
-
9Assets/UIWidgets/promise/Promise_NonGeneric.cs
-
28Assets/UIWidgets/rendering/binding.cs
-
5Assets/UIWidgets/rendering/editable.cs
-
46Assets/UIWidgets/rendering/object.cs
-
6Assets/UIWidgets/rendering/object.mixin.gen.cs
-
2Assets/UIWidgets/rendering/object.mixin.njk
-
45Assets/UIWidgets/rendering/proxy_box.cs
-
33Assets/UIWidgets/rendering/sliver_fixed_extent_list.cs
-
4Assets/UIWidgets/rendering/sliver_list.cs
-
6Assets/UIWidgets/rendering/sliver_multi_box_adaptor.cs
-
6Assets/UIWidgets/rendering/sliver_padding.cs
-
2Assets/UIWidgets/rendering/view.cs
-
6Assets/UIWidgets/rendering/viewpoint.cs
-
6Assets/UIWidgets/rendering/viewport_offset.cs
-
32Assets/UIWidgets/scheduler/binding.cs
-
21Assets/UIWidgets/scheduler/ticker.cs
-
20Assets/UIWidgets/ui/window.cs
-
155Assets/UIWidgets/widgets/basic.cs
-
221Assets/UIWidgets/widgets/binding.cs
-
25Assets/UIWidgets/widgets/debug.cs
-
42Assets/UIWidgets/widgets/framework.cs
-
2Assets/UIWidgets/widgets/scroll_activity.cs
-
16Assets/UIWidgets/widgets/scroll_metrics.cs
-
497Assets/UIWidgets/widgets/scroll_position.cs
-
172Assets/UIWidgets/widgets/ticker_provider.cs
-
31Assets/UIWidgets/gestures/long_press.cs
-
3Assets/UIWidgets/gestures/long_press.cs.meta
-
206Assets/UIWidgets/rendering/automatic_keep_alive.cs
-
3Assets/UIWidgets/rendering/automatic_keep_alive.cs.meta
-
380Assets/UIWidgets/widgets/gesture_detector.cs
-
3Assets/UIWidgets/widgets/gesture_detector.cs.meta
-
144Assets/UIWidgets/widgets/page_storage.cs
-
3Assets/UIWidgets/widgets/page_storage.cs.meta
-
45Assets/UIWidgets/widgets/primary_scroll_controller.cs
-
3Assets/UIWidgets/widgets/primary_scroll_controller.cs.meta
-
58Assets/UIWidgets/widgets/scroll_configuration.cs
-
3Assets/UIWidgets/widgets/scroll_configuration.cs.meta
-
192Assets/UIWidgets/widgets/scroll_controller.cs
-
3Assets/UIWidgets/widgets/scroll_controller.cs.meta
-
205Assets/UIWidgets/widgets/scroll_position_with_single_context.cs
-
3Assets/UIWidgets/widgets/scroll_position_with_single_context.cs.meta
-
437Assets/UIWidgets/widgets/scroll_view.cs
-
3Assets/UIWidgets/widgets/scroll_view.cs.meta
-
391Assets/UIWidgets/widgets/scrollable.cs
-
3Assets/UIWidgets/widgets/scrollable.cs.meta
-
519Assets/UIWidgets/widgets/sliver.cs
-
3Assets/UIWidgets/widgets/sliver.cs.meta
-
189Assets/UIWidgets/widgets/viewport.cs
-
3Assets/UIWidgets/widgets/viewport.cs.meta
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using RSG; |
|||
using UIWidgets.animation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.physics; |
|||
// public abstract class ScrollPosition : ViewportOffset, ScrollMetrics {
|
|||
// ScrollPosition(
|
|||
// ScrollPhysics physics = null,
|
|||
// ScrollContext context = null,
|
|||
// bool keepScrollOffset = true,
|
|||
// ScrollPosition oldPosition = null,
|
|||
// string debugLabel = null
|
|||
// ) {
|
|||
// D.assert(physics != null);
|
|||
// D.assert(context != null);
|
|||
// D.assert(context.vsync != null);
|
|||
//
|
|||
// this.physics = physics;
|
|||
// this.context = context;
|
|||
// this.keepScrollOffset = keepScrollOffset;
|
|||
// this.debugLabel = debugLabel;
|
|||
//
|
|||
// if (oldPosition != null) {
|
|||
// this.absorb(oldPosition);
|
|||
// }
|
|||
//
|
|||
// if (keepScrollOffset) {
|
|||
// this.restoreScrollOffset();
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// public readonly ScrollPhysics physics;
|
|||
// public readonly ScrollContext context;
|
|||
// public readonly bool keepScrollOffset;
|
|||
// public readonly string debugLabel;
|
|||
//
|
|||
// public double minScrollExtent {
|
|||
// get { return this._minScrollExtent; }
|
|||
// }
|
|||
//
|
|||
// double _minScrollExtent;
|
|||
//
|
|||
// public double maxScrollExtent {
|
|||
// get { return this._maxScrollExtent; }
|
|||
// }
|
|||
//
|
|||
// double _maxScrollExtent;
|
|||
//
|
|||
// public override double? pixels {
|
|||
// get { return this._pixels; }
|
|||
// }
|
|||
//
|
|||
// double? _pixels;
|
|||
//
|
|||
// public double viewportDimension {
|
|||
// get { return this._viewportDimension; }
|
|||
// }
|
|||
//
|
|||
// double _viewportDimension;
|
|||
//
|
|||
// public bool haveDimensions {
|
|||
// get { return this._haveDimensions; }
|
|||
// }
|
|||
//
|
|||
// bool _haveDimensions = false;
|
|||
//
|
|||
// protected virtual void absorb(ScrollPosition other) {
|
|||
// D.assert(other != null);
|
|||
// D.assert(other.context == context);
|
|||
// D.assert(_pixels == null);
|
|||
// _minScrollExtent = other.minScrollExtent;
|
|||
// _maxScrollExtent = other.maxScrollExtent;
|
|||
// _pixels = other._pixels;
|
|||
// _viewportDimension = other.viewportDimension;
|
|||
//
|
|||
// D.assert(activity == null);
|
|||
// D.assert(other.activity != null);
|
|||
// _activity = other.activity;
|
|||
// other._activity = null;
|
|||
// if (other.runtimeType != runtimeType)
|
|||
// activity.resetActivity();
|
|||
// context.setIgnorePointer(activity.shouldIgnorePointer);
|
|||
// isScrollingNotifier.value = activity.isScrolling;
|
|||
// }
|
|||
//
|
|||
// public double setPixels(double newPixels) {
|
|||
// D.assert(this._pixels != null);
|
|||
// D.assert(this.context.vsync.schedulerBinding.schedulerPhase <= SchedulerPhase.transientCallbacks);
|
|||
// if (newPixels != this.pixels) {
|
|||
// double overscroll = this.applyBoundaryConditions(newPixels);
|
|||
// D.assert(() => {
|
|||
// double delta = newPixels - this.pixels;
|
|||
// if (overscroll.abs() > delta.abs()) {
|
|||
// throw new UIWidgetsError(
|
|||
// string.Format(
|
|||
// "{0}.applyBoundaryConditions returned invalid overscroll value.\n" +
|
|||
// "setPixels() was called to change the scroll offset from {1} to {2}.\n" +
|
|||
// "That is a delta of {3} units.\n" +
|
|||
// "{0}.applyBoundaryConditions reported an overscroll of {4} units."
|
|||
// , this.GetType(), this.pixels, newPixels, delta, overscroll));
|
|||
// }
|
|||
//
|
|||
// return true;
|
|||
// });
|
|||
//
|
|||
// double oldPixels = this.pixels;
|
|||
// this._pixels = newPixels - overscroll;
|
|||
// if (this._pixels != oldPixels) {
|
|||
// this.notifyListeners();
|
|||
// this.didUpdateScrollPositionBy(this._pixels - oldPixels);
|
|||
// }
|
|||
//
|
|||
// if (overscroll != 0.0) {
|
|||
// this.didOverscrollBy(overscroll);
|
|||
// return overscroll;
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// return 0.0;
|
|||
// }
|
|||
//
|
|||
// public void correctPixels(double value) {
|
|||
// this._pixels = value;
|
|||
// }
|
|||
//
|
|||
// public override void correctBy(double correction) {
|
|||
// D.assert(
|
|||
// this._pixels != null,
|
|||
// "An initial pixels value must exist by caling correctPixels on the ScrollPosition"
|
|||
// );
|
|||
//
|
|||
// this._pixels += correction;
|
|||
// this._didChangeViewportDimensionOrReceiveCorrection = true;
|
|||
// }
|
|||
//
|
|||
// protected void forcePixels(double value) {
|
|||
// D.assert(this.pixels != null);
|
|||
// _pixels = value;
|
|||
// notifyListeners();
|
|||
// }
|
|||
//
|
|||
// protected void saveScrollOffset() {
|
|||
// PageStorage.of(context.storageContext)?.writeState(context.storageContext, pixels);
|
|||
// }
|
|||
//
|
|||
// protected void restoreScrollOffset() {
|
|||
// if (pixels == null) {
|
|||
// final double value = PageStorage.of(context.storageContext)?.readState(context.storageContext);
|
|||
// if (value != null)
|
|||
// correctPixels(value);
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
public abstract class ScrollPosition : ViewportOffset, ScrollMetrics { |
|||
protected ScrollPosition( |
|||
ScrollPhysics physics = null, |
|||
ScrollContext context = null, |
|||
bool keepScrollOffset = true, |
|||
ScrollPosition oldPosition = null, |
|||
string debugLabel = null |
|||
) { |
|||
D.assert(physics != null); |
|||
D.assert(context != null); |
|||
D.assert(context.vsync != null); |
|||
|
|||
this.physics = physics; |
|||
this.context = context; |
|||
this.keepScrollOffset = keepScrollOffset; |
|||
this.debugLabel = debugLabel; |
|||
|
|||
if (oldPosition != null) { |
|||
this.absorb(oldPosition); |
|||
} |
|||
|
|||
if (keepScrollOffset) { |
|||
this.restoreScrollOffset(); |
|||
} |
|||
} |
|||
|
|||
public readonly ScrollPhysics physics; |
|||
|
|||
public readonly ScrollContext context; |
|||
|
|||
public readonly bool keepScrollOffset; |
|||
|
|||
public readonly string debugLabel; |
|||
|
|||
public double minScrollExtent { |
|||
get { return this._minScrollExtent.Value; } |
|||
} |
|||
|
|||
double? _minScrollExtent; |
|||
|
|||
public double maxScrollExtent { |
|||
get { return this._maxScrollExtent.Value; } |
|||
} |
|||
|
|||
double? _maxScrollExtent; |
|||
|
|||
public override double pixels { |
|||
get { |
|||
D.assert(this._pixels != null); |
|||
return this._pixels ?? 0.0; |
|||
} |
|||
} |
|||
|
|||
internal double? _pixels; |
|||
|
|||
public double viewportDimension { |
|||
get { return this._viewportDimension.Value; } |
|||
} |
|||
|
|||
double? _viewportDimension; |
|||
|
|||
public bool haveDimensions { |
|||
get { return this._haveDimensions; } |
|||
} |
|||
|
|||
bool _haveDimensions = false; |
|||
|
|||
public abstract AxisDirection axisDirection { get; } |
|||
|
|||
protected virtual void absorb(ScrollPosition other) { |
|||
D.assert(other != null); |
|||
D.assert(other.context == this.context); |
|||
D.assert(this._pixels == null); |
|||
this._minScrollExtent = other.minScrollExtent; |
|||
this._maxScrollExtent = other.maxScrollExtent; |
|||
this._pixels = other._pixels; |
|||
this._viewportDimension = other.viewportDimension; |
|||
|
|||
D.assert(this.activity == null); |
|||
D.assert(other.activity != null); |
|||
this._activity = other.activity; |
|||
other._activity = null; |
|||
if (other.GetType() != this.GetType()) { |
|||
this.activity.resetActivity(); |
|||
} |
|||
|
|||
this.context.setIgnorePointer(this.activity.shouldIgnorePointer); |
|||
this.isScrollingNotifier.value = this.activity.isScrolling; |
|||
} |
|||
|
|||
public virtual double setPixels(double newPixels) { |
|||
D.assert(this._pixels != null); |
|||
D.assert(SchedulerBinding.instance.schedulerPhase <= SchedulerPhase.transientCallbacks); |
|||
if (newPixels != this.pixels) { |
|||
double overscroll = this.applyBoundaryConditions(newPixels); |
|||
D.assert(() => { |
|||
double delta = newPixels - this.pixels; |
|||
if (overscroll.abs() > delta.abs()) { |
|||
throw new UIWidgetsError( |
|||
string.Format( |
|||
"{0}.applyBoundaryConditions returned invalid overscroll value.\n" + |
|||
"setPixels() was called to change the scroll offset from {1} to {2}.\n" + |
|||
"That is a delta of {3} units.\n" + |
|||
"{0}.applyBoundaryConditions reported an overscroll of {4} units." |
|||
, this.GetType(), this.pixels, newPixels, delta, overscroll)); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
|
|||
double oldPixels = this.pixels; |
|||
this._pixels = newPixels - overscroll; |
|||
if (this.pixels != oldPixels) { |
|||
this.notifyListeners(); |
|||
this.didUpdateScrollPositionBy(this.pixels - oldPixels); |
|||
} |
|||
|
|||
if (overscroll != 0.0) { |
|||
this.didOverscrollBy(overscroll); |
|||
return overscroll; |
|||
} |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
public void correctPixels(double value) { |
|||
this._pixels = value; |
|||
} |
|||
|
|||
public override void correctBy(double correction) { |
|||
D.assert( |
|||
this._pixels != null, |
|||
"An initial pixels value must exist by caling correctPixels on the ScrollPosition" |
|||
); |
|||
|
|||
this._pixels += correction; |
|||
this._didChangeViewportDimensionOrReceiveCorrection = true; |
|||
} |
|||
|
|||
protected void forcePixels(double value) { |
|||
D.assert(this._pixels != null); |
|||
this._pixels = value; |
|||
this.notifyListeners(); |
|||
} |
|||
|
|||
protected void saveScrollOffset() { |
|||
var pageStorage = PageStorage.of(this.context.storageContext); |
|||
if (pageStorage != null) { |
|||
pageStorage.writeState(this.context.storageContext, this.pixels); |
|||
} |
|||
} |
|||
|
|||
protected void restoreScrollOffset() { |
|||
if (this._pixels == null) { |
|||
var pageStorage = PageStorage.of(this.context.storageContext); |
|||
if (pageStorage != null) { |
|||
object valueRaw = pageStorage.readState(this.context.storageContext); |
|||
if (valueRaw != null) { |
|||
this.correctPixels((double) valueRaw); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected double applyBoundaryConditions(double value) { |
|||
double result = this.physics.applyBoundaryConditions(this, value); |
|||
D.assert(() => { |
|||
double delta = value - this.pixels; |
|||
if (result.abs() > delta.abs()) { |
|||
throw new UIWidgetsError( |
|||
string.Format( |
|||
"{0}.applyBoundaryConditions returned invalid overscroll value.\n" + |
|||
"The method was called to consider a change from {1} to {2}, which is a " + |
|||
"delta of {3:F1} units. However, it returned an overscroll of " + |
|||
"${4:F1} units, which has a greater magnitude than the delta. " + |
|||
"The applyBoundaryConditions method is only supposed to reduce the possible range " + |
|||
"of movement, not increase it.\n" + |
|||
"The scroll extents are {5} .. {6}, and the " + |
|||
"viewport dimension is {7}.", |
|||
this.physics.GetType(), this.pixels, value, delta, result, |
|||
this.minScrollExtent, this.maxScrollExtent, this.viewportDimension)); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bool _didChangeViewportDimensionOrReceiveCorrection = true; |
|||
|
|||
public override bool applyViewportDimension(double viewportDimension) { |
|||
if (this._viewportDimension != viewportDimension) { |
|||
this._viewportDimension = viewportDimension; |
|||
this._didChangeViewportDimensionOrReceiveCorrection = true; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public override bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { |
|||
if (!PhysicsUtils.nearEqual(this._minScrollExtent, minScrollExtent, Tolerance.defaultTolerance.distance) || |
|||
!PhysicsUtils.nearEqual(this._maxScrollExtent, maxScrollExtent, Tolerance.defaultTolerance.distance) || |
|||
this._didChangeViewportDimensionOrReceiveCorrection) { |
|||
this._minScrollExtent = minScrollExtent; |
|||
this._maxScrollExtent = maxScrollExtent; |
|||
this._haveDimensions = true; |
|||
this.applyNewDimensions(); |
|||
this._didChangeViewportDimensionOrReceiveCorrection = false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
protected virtual void applyNewDimensions() { |
|||
D.assert(this._pixels != null); |
|||
this.activity.applyNewDimensions(); |
|||
} |
|||
|
|||
public IPromise ensureVisible(RenderObject renderObject, |
|||
double alignment = 0.0, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null |
|||
) { |
|||
D.assert(renderObject.attached); |
|||
RenderAbstractViewport viewport = RenderAbstractViewportUtils.of(renderObject); |
|||
D.assert(viewport != null); |
|||
|
|||
double target = viewport.getOffsetToReveal(renderObject, alignment).offset.clamp( |
|||
this.minScrollExtent, this.maxScrollExtent); |
|||
|
|||
if (target == this.pixels) { |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
duration = duration ?? TimeSpan.Zero; |
|||
if (duration == TimeSpan.Zero) { |
|||
this.jumpTo(target); |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
curve = curve ?? Curves.ease; |
|||
return this.animateTo(target, duration: duration.Value, curve: curve); |
|||
} |
|||
|
|||
public readonly ValueNotifier<bool> isScrollingNotifier = new ValueNotifier<bool>(false); |
|||
|
|||
public override bool allowImplicitScrolling { |
|||
get { return this.physics.allowImplicitScrolling; } |
|||
} |
|||
|
|||
public abstract ScrollHoldController hold(VoidCallback holdCancelCallback); |
|||
|
|||
public abstract Drag drag(DragStartDetails details, VoidCallback dragCancelCallback); |
|||
|
|||
protected ScrollActivity activity { |
|||
get { return this._activity; } |
|||
} |
|||
|
|||
ScrollActivity _activity; |
|||
|
|||
public virtual void beginActivity(ScrollActivity newActivity) { |
|||
if (newActivity == null) { |
|||
return; |
|||
} |
|||
|
|||
bool wasScrolling, oldIgnorePointer; |
|||
if (this._activity != null) { |
|||
oldIgnorePointer = this._activity.shouldIgnorePointer; |
|||
wasScrolling = this._activity.isScrolling; |
|||
if (wasScrolling && !newActivity.isScrolling) { |
|||
this.didEndScroll(); |
|||
} |
|||
|
|||
this._activity.dispose(); |
|||
} else { |
|||
oldIgnorePointer = false; |
|||
wasScrolling = false; |
|||
} |
|||
|
|||
this._activity = newActivity; |
|||
if (oldIgnorePointer != this.activity.shouldIgnorePointer) { |
|||
this.context.setIgnorePointer(this.activity.shouldIgnorePointer); |
|||
} |
|||
|
|||
this.isScrollingNotifier.value = this.activity.isScrolling; |
|||
if (!wasScrolling && this._activity.isScrolling) { |
|||
this.didStartScroll(); |
|||
} |
|||
} |
|||
|
|||
public void didStartScroll() { |
|||
this.activity.dispatchScrollStartNotification( |
|||
ScrollMetricsUtils.copyWith(this), this.context.notificationContext); |
|||
} |
|||
|
|||
public void didUpdateScrollPositionBy(double delta) { |
|||
this.activity.dispatchScrollUpdateNotification( |
|||
ScrollMetricsUtils.copyWith(this), this.context.notificationContext, delta); |
|||
} |
|||
|
|||
public void didEndScroll() { |
|||
this.activity.dispatchScrollEndNotification( |
|||
ScrollMetricsUtils.copyWith(this), this.context.notificationContext); |
|||
if (this.keepScrollOffset) { |
|||
this.saveScrollOffset(); |
|||
} |
|||
} |
|||
|
|||
public void didOverscrollBy(double value) { |
|||
D.assert(this.activity.isScrolling); |
|||
this.activity.dispatchOverscrollNotification( |
|||
ScrollMetricsUtils.copyWith(this), this.context.notificationContext, value); |
|||
} |
|||
|
|||
public void didUpdateScrollDirection(ScrollDirection direction) { |
|||
new UserScrollNotification(metrics: |
|||
ScrollMetricsUtils.copyWith(this), context: this.context.notificationContext, direction: direction |
|||
).dispatch(this.context.notificationContext); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
D.assert(this._pixels != null); |
|||
if (this.activity != null) { |
|||
this.activity.dispose(); |
|||
this._activity = null; |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
protected override void debugFillDescription(List<String> description) { |
|||
if (this.debugLabel != null) { |
|||
description.Add(this.debugLabel); |
|||
} |
|||
|
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("range: {0:F1}..{1:F1}", this._minScrollExtent, this._maxScrollExtent)); |
|||
description.Add(string.Format("viewport: {0:F1}", this._viewportDimension)); |
|||
} |
|||
} |
|||
} |
|
|||
namespace UIWidgets.gestures { |
|||
public delegate void GestureLongPressCallback(); |
|||
|
|||
public class LongPressGestureRecognizer : PrimaryPointerGestureRecognizer { |
|||
public LongPressGestureRecognizer(object debugOwner = null) : |
|||
base(deadline: Constants.kLongPressTimeout, debugOwner: debugOwner) { |
|||
} |
|||
|
|||
public GestureLongPressCallback onLongPress; |
|||
|
|||
protected override void didExceedDeadline() { |
|||
this.resolve(GestureDisposition.accepted); |
|||
if (this.onLongPress != null) { |
|||
this.invokeCallback<object>("onLongPress", () => { |
|||
this.onLongPress(); |
|||
return null; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
protected override void handlePrimaryPointer(PointerEvent evt) { |
|||
if (evt is PointerUpEvent) { |
|||
this.resolve(GestureDisposition.rejected); |
|||
} |
|||
} |
|||
|
|||
public override string debugDescription { |
|||
get { return "long press"; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3315b2f4cd844e3c81aa0f074b4914a3 |
|||
timeCreated: 1537166837 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.scheduler; |
|||
using UIWidgets.ui; |
|||
using UIWidgets.widgets; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public class AutomaticKeepAlive : StatefulWidget { |
|||
public AutomaticKeepAlive( |
|||
Key key = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override State createState() { |
|||
return new _AutomaticKeepAliveState(); |
|||
} |
|||
} |
|||
|
|||
class _AutomaticKeepAliveState : State<AutomaticKeepAlive> { |
|||
Dictionary<Listenable, VoidCallback> _handles; |
|||
Widget _child; |
|||
bool _keepingAlive = false; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._updateChild(); |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
this._updateChild(); |
|||
} |
|||
|
|||
void _updateChild() { |
|||
this._child = new NotificationListener<KeepAliveNotification>( |
|||
onNotification: this._addClient, |
|||
child: this.widget.child |
|||
); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this._handles != null) { |
|||
foreach (Listenable handle in this._handles.Keys) |
|||
handle.removeListener(this._handles[handle]); |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
bool _addClient(KeepAliveNotification notification) { |
|||
Listenable handle = notification.handle; |
|||
this._handles = this._handles ?? new Dictionary<Listenable, VoidCallback>(); |
|||
|
|||
D.assert(!this._handles.ContainsKey(handle)); |
|||
this._handles[handle] = this._createCallback(handle); |
|||
handle.addListener(this._handles[handle]); |
|||
if (!this._keepingAlive) { |
|||
this._keepingAlive = true; |
|||
ParentDataElement<SliverMultiBoxAdaptorWidget> childElement = this._getChildElement(); |
|||
if (childElement != null) { |
|||
this._updateParentDataOfChild(childElement); |
|||
} else { |
|||
SchedulerBinding.instance.addPostFrameCallback(timeStamp => { |
|||
ParentDataElement<SliverMultiBoxAdaptorWidget> childElement1 = this._getChildElement(); |
|||
D.assert(childElement1 != null); |
|||
this._updateParentDataOfChild(childElement1); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
ParentDataElement<SliverMultiBoxAdaptorWidget> _getChildElement() { |
|||
Element element = (Element) this.context; |
|||
Element childElement = null; |
|||
element.visitChildren((Element child) => { childElement = child; }); |
|||
|
|||
D.assert(childElement == null || childElement is ParentDataElement<SliverMultiBoxAdaptorWidget>); |
|||
return (ParentDataElement<SliverMultiBoxAdaptorWidget>) childElement; |
|||
} |
|||
|
|||
void _updateParentDataOfChild(ParentDataElement<SliverMultiBoxAdaptorWidget> childElement) { |
|||
childElement.applyWidgetOutOfTurn((ParentDataWidget<SliverMultiBoxAdaptorWidget>) this.build(this.context)); |
|||
} |
|||
|
|||
VoidCallback _createCallback(Listenable handle) { |
|||
return () => { |
|||
D.assert(() => { |
|||
if (!this.mounted) { |
|||
throw new UIWidgetsError( |
|||
"AutomaticKeepAlive handle triggered after AutomaticKeepAlive was disposed." + |
|||
"Widgets should always trigger their KeepAliveNotification handle when they are " + |
|||
"deactivated, so that they (or their handle) do not send spurious events later " + |
|||
"when they are no longer in the tree." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
this._handles.Remove(handle); |
|||
if (this._handles.isEmpty()) { |
|||
if (SchedulerBinding.instance.schedulerPhase < SchedulerPhase.persistentCallbacks) { |
|||
this.setState(() => { this._keepingAlive = false; }); |
|||
} else { |
|||
this._keepingAlive = false; |
|||
Window.instance.scheduleMicrotask(() => { |
|||
if (this.mounted && this._handles.isEmpty()) { |
|||
this.setState(() => { D.assert(!this._keepingAlive); }); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(this._child != null); |
|||
return new KeepAlive( |
|||
keepAlive: this._keepingAlive, |
|||
child: this._child |
|||
); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder description) { |
|||
base.debugFillProperties(description); |
|||
description.add(new FlagProperty("_keepingAlive", value: this._keepingAlive, |
|||
ifTrue: "keeping subtree alive")); |
|||
description.add(new DiagnosticsProperty<Dictionary<Listenable, VoidCallback>>( |
|||
"handles", |
|||
this._handles, |
|||
description: this._handles != null ? this._handles.Count + " active clients" : null, |
|||
ifNull: "no notifications ever received" |
|||
)); |
|||
} |
|||
} |
|||
|
|||
public class KeepAliveNotification : Notification { |
|||
public KeepAliveNotification(Listenable handle) { |
|||
D.assert(handle != null); |
|||
this.handle = handle; |
|||
} |
|||
|
|||
public readonly Listenable handle; |
|||
} |
|||
|
|||
public class KeepAliveHandle : ChangeNotifier { |
|||
public void release() { |
|||
this.notifyListeners(); |
|||
} |
|||
} |
|||
|
|||
public abstract class AutomaticKeepAliveClientMixin<T> : State<T> where T : StatefulWidget { |
|||
KeepAliveHandle _keepAliveHandle; |
|||
|
|||
void _ensureKeepAlive() { |
|||
D.assert(this._keepAliveHandle == null); |
|||
this._keepAliveHandle = new KeepAliveHandle(); |
|||
new KeepAliveNotification(this._keepAliveHandle).dispatch(this.context); |
|||
} |
|||
|
|||
void _releaseKeepAlive() { |
|||
this._keepAliveHandle.release(); |
|||
this._keepAliveHandle = null; |
|||
} |
|||
|
|||
protected abstract bool wantKeepAlive { get; } |
|||
|
|||
protected void updateKeepAlive() { |
|||
if (this.wantKeepAlive) { |
|||
if (this._keepAliveHandle == null) |
|||
this._ensureKeepAlive(); |
|||
} else { |
|||
if (this._keepAliveHandle != null) |
|||
this._releaseKeepAlive(); |
|||
} |
|||
} |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
if (this.wantKeepAlive) { |
|||
this._ensureKeepAlive(); |
|||
} |
|||
} |
|||
|
|||
public override void deactivate() { |
|||
if (this._keepAliveHandle != null) { |
|||
this._releaseKeepAlive(); |
|||
} |
|||
|
|||
base.deactivate(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
if (this.wantKeepAlive && this._keepAliveHandle == null) { |
|||
this._ensureKeepAlive(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a3c3b140ce174c61bfd25672b4ad6f21 |
|||
timeCreated: 1537325090 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public abstract class GestureRecognizerFactory { |
|||
public abstract GestureRecognizer constructorRaw(); |
|||
|
|||
public abstract void initializerRaw(GestureRecognizer instance); |
|||
|
|||
internal abstract bool _debugAssertTypeMatches(Type type); |
|||
} |
|||
|
|||
public abstract class GestureRecognizerFactory<T> : GestureRecognizerFactory where T : GestureRecognizer { |
|||
public override GestureRecognizer constructorRaw() { |
|||
return this.constructor(); |
|||
} |
|||
|
|||
public override void initializerRaw(GestureRecognizer instance) { |
|||
this.initializer((T) instance); |
|||
} |
|||
|
|||
public abstract T constructor(); |
|||
|
|||
public abstract void initializer(T instance); |
|||
|
|||
internal override bool _debugAssertTypeMatches(Type type) { |
|||
D.assert(type == typeof(T), |
|||
"GestureRecognizerFactory of type " + typeof(T) + " was used where type $type was specified."); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public delegate T GestureRecognizerFactoryConstructor<T>() where T : GestureRecognizer; |
|||
|
|||
public delegate void GestureRecognizerFactoryInitializer<T>(T instance) where T : GestureRecognizer; |
|||
|
|||
public class GestureRecognizerFactoryWithHandlers<T> : GestureRecognizerFactory<T> where T : GestureRecognizer { |
|||
public GestureRecognizerFactoryWithHandlers(GestureRecognizerFactoryConstructor<T> constructor, |
|||
GestureRecognizerFactoryInitializer<T> initializer) { |
|||
D.assert(constructor != null); |
|||
D.assert(initializer != null); |
|||
|
|||
this._constructor = constructor; |
|||
this._initializer = initializer; |
|||
} |
|||
|
|||
readonly GestureRecognizerFactoryConstructor<T> _constructor; |
|||
|
|||
readonly GestureRecognizerFactoryInitializer<T> _initializer; |
|||
|
|||
public override T constructor() { |
|||
return this._constructor(); |
|||
} |
|||
|
|||
public override void initializer(T instance) { |
|||
this._initializer(instance); |
|||
} |
|||
} |
|||
|
|||
public class GestureDetector : StatelessWidget { |
|||
public GestureDetector( |
|||
Key key = null, |
|||
Widget child = null, |
|||
GestureTapDownCallback onTapDown = null, |
|||
GestureTapUpCallback onTapUp = null, |
|||
GestureTapCallback onTap = null, |
|||
GestureTapCancelCallback onTapCancel = null, |
|||
GestureDoubleTapCallback onDoubleTap = null, |
|||
GestureLongPressCallback onLongPress = null, |
|||
GestureDragDownCallback onVerticalDragDown = null, |
|||
GestureDragStartCallback onVerticalDragStart = null, |
|||
GestureDragUpdateCallback onVerticalDragUpdate = null, |
|||
GestureDragEndCallback onVerticalDragEnd = null, |
|||
GestureDragCancelCallback onVerticalDragCancel = null, |
|||
GestureDragDownCallback onHorizontalDragDown = null, |
|||
GestureDragStartCallback onHorizontalDragStart = null, |
|||
GestureDragUpdateCallback onHorizontalDragUpdate = null, |
|||
GestureDragEndCallback onHorizontalDragEnd = null, |
|||
GestureDragCancelCallback onHorizontalDragCancel = null, |
|||
GestureDragDownCallback onPanDown = null, |
|||
GestureDragStartCallback onPanStart = null, |
|||
GestureDragUpdateCallback onPanUpdate = null, |
|||
GestureDragEndCallback onPanEnd = null, |
|||
GestureDragCancelCallback onPanCancel = null, |
|||
HitTestBehavior behavior = HitTestBehavior.deferToChild) : base(key) { |
|||
D.assert(() => { |
|||
bool haveVerticalDrag = |
|||
onVerticalDragStart != null || onVerticalDragUpdate != null || |
|||
onVerticalDragEnd != null; |
|||
bool haveHorizontalDrag = |
|||
onHorizontalDragStart != null || onHorizontalDragUpdate != null || |
|||
onHorizontalDragEnd != null; |
|||
bool havePan = onPanStart != null || onPanUpdate != null || onPanEnd != null; |
|||
if (havePan) { |
|||
if (haveVerticalDrag && haveHorizontalDrag) { |
|||
throw new UIWidgetsError( |
|||
"Incorrect GestureDetector arguments.\n" + |
|||
"Simultaneously having a vertical drag gesture recognizer, a horizontal drag gesture recognizer, and a pan gesture recognizer " + |
|||
"will result in the pan gesture recognizer being ignored, since the other two will catch all drags." |
|||
); |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
|
|||
this.child = child; |
|||
this.onTapDown = onTapDown; |
|||
this.onTapUp = onTapUp; |
|||
this.onTap = onTap; |
|||
this.onTapCancel = onTapCancel; |
|||
this.onDoubleTap = onDoubleTap; |
|||
this.onLongPress = onLongPress; |
|||
this.onVerticalDragDown = onVerticalDragDown; |
|||
this.onVerticalDragStart = onVerticalDragStart; |
|||
this.onVerticalDragUpdate = onVerticalDragUpdate; |
|||
this.onVerticalDragEnd = onVerticalDragEnd; |
|||
this.onVerticalDragCancel = onVerticalDragCancel; |
|||
this.onHorizontalDragDown = onHorizontalDragDown; |
|||
this.onHorizontalDragStart = onHorizontalDragStart; |
|||
this.onHorizontalDragUpdate = onHorizontalDragUpdate; |
|||
this.onHorizontalDragEnd = onHorizontalDragEnd; |
|||
this.onHorizontalDragCancel = onHorizontalDragCancel; |
|||
this.onPanDown = onPanDown; |
|||
this.onPanStart = onPanStart; |
|||
this.onPanUpdate = onPanUpdate; |
|||
this.onPanEnd = onPanEnd; |
|||
this.onPanCancel = onPanCancel; |
|||
this.behavior = behavior; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
public readonly GestureTapDownCallback onTapDown; |
|||
public readonly GestureTapUpCallback onTapUp; |
|||
public readonly GestureTapCallback onTap; |
|||
public readonly GestureTapCancelCallback onTapCancel; |
|||
public readonly GestureDoubleTapCallback onDoubleTap; |
|||
public readonly GestureLongPressCallback onLongPress; |
|||
public readonly GestureDragDownCallback onVerticalDragDown; |
|||
public readonly GestureDragStartCallback onVerticalDragStart; |
|||
public readonly GestureDragUpdateCallback onVerticalDragUpdate; |
|||
public readonly GestureDragEndCallback onVerticalDragEnd; |
|||
public readonly GestureDragCancelCallback onVerticalDragCancel; |
|||
public readonly GestureDragDownCallback onHorizontalDragDown; |
|||
public readonly GestureDragStartCallback onHorizontalDragStart; |
|||
public readonly GestureDragUpdateCallback onHorizontalDragUpdate; |
|||
public readonly GestureDragEndCallback onHorizontalDragEnd; |
|||
public readonly GestureDragCancelCallback onHorizontalDragCancel; |
|||
public readonly GestureDragDownCallback onPanDown; |
|||
public readonly GestureDragStartCallback onPanStart; |
|||
public readonly GestureDragUpdateCallback onPanUpdate; |
|||
public readonly GestureDragEndCallback onPanEnd; |
|||
public readonly GestureDragCancelCallback onPanCancel; |
|||
public readonly HitTestBehavior behavior; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
var gestures = new Dictionary<Type, GestureRecognizerFactory>(); |
|||
|
|||
if (this.onTapDown != null || |
|||
this.onTapUp != null || |
|||
this.onTap != null || |
|||
this.onTapCancel != null) { |
|||
gestures[typeof(TapGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>( |
|||
() => new TapGestureRecognizer(debugOwner: this), |
|||
instance => { |
|||
instance.onTapDown = this.onTapDown; |
|||
instance.onTapUp = this.onTapUp; |
|||
instance.onTap = this.onTap; |
|||
instance.onTapCancel = this.onTapCancel; |
|||
} |
|||
); |
|||
} |
|||
|
|||
if (this.onDoubleTap != null) { |
|||
gestures[typeof(DoubleTapGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<DoubleTapGestureRecognizer>( |
|||
() => new DoubleTapGestureRecognizer(debugOwner: this), |
|||
instance => { instance.onDoubleTap = this.onDoubleTap; } |
|||
); |
|||
} |
|||
|
|||
if (this.onLongPress != null) { |
|||
gestures[typeof(LongPressGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>( |
|||
() => new LongPressGestureRecognizer(debugOwner: this), |
|||
instance => { instance.onLongPress = this.onLongPress; } |
|||
); |
|||
} |
|||
|
|||
if (this.onVerticalDragDown != null || |
|||
this.onVerticalDragStart != null || |
|||
this.onVerticalDragUpdate != null || |
|||
this.onVerticalDragEnd != null || |
|||
this.onVerticalDragCancel != null) { |
|||
gestures[typeof(VerticalDragGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>( |
|||
() => new VerticalDragGestureRecognizer(debugOwner: this), |
|||
instance => { |
|||
instance.onDown = this.onVerticalDragDown; |
|||
instance.onStart = this.onVerticalDragStart; |
|||
instance.onUpdate = this.onVerticalDragUpdate; |
|||
instance.onEnd = this.onVerticalDragEnd; |
|||
instance.onCancel = this.onVerticalDragCancel; |
|||
} |
|||
); |
|||
} |
|||
|
|||
if (this.onHorizontalDragDown != null || |
|||
this.onHorizontalDragStart != null || |
|||
this.onHorizontalDragUpdate != null || |
|||
this.onHorizontalDragEnd != null || |
|||
this.onHorizontalDragCancel != null) { |
|||
gestures[typeof(HorizontalDragGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>( |
|||
() => new HorizontalDragGestureRecognizer(debugOwner: this), |
|||
instance => { |
|||
instance.onDown = this.onHorizontalDragDown; |
|||
instance.onStart = this.onHorizontalDragStart; |
|||
instance.onUpdate = this.onHorizontalDragUpdate; |
|||
instance.onEnd = this.onHorizontalDragEnd; |
|||
instance.onCancel = this.onHorizontalDragCancel; |
|||
} |
|||
); |
|||
} |
|||
|
|||
if (this.onPanDown != null || |
|||
this.onPanStart != null || |
|||
this.onPanUpdate != null || |
|||
this.onPanEnd != null || |
|||
this.onPanCancel != null) { |
|||
gestures[typeof(PanGestureRecognizer)] = |
|||
new GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>( |
|||
() => new PanGestureRecognizer(debugOwner: this), |
|||
instance => { |
|||
instance.onDown = this.onPanDown; |
|||
instance.onStart = this.onPanStart; |
|||
instance.onUpdate = this.onPanUpdate; |
|||
instance.onEnd = this.onPanEnd; |
|||
instance.onCancel = this.onPanCancel; |
|||
} |
|||
); |
|||
} |
|||
|
|||
return new RawGestureDetector( |
|||
gestures: gestures, |
|||
behavior: this.behavior, |
|||
child: this.child |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class RawGestureDetector : StatefulWidget { |
|||
public RawGestureDetector( |
|||
Key key = null, |
|||
Widget child = null, |
|||
Dictionary<Type, GestureRecognizerFactory> gestures = null, |
|||
HitTestBehavior? behavior = null |
|||
) : base(key: key) { |
|||
D.assert(gestures != null); |
|||
this.child = child; |
|||
this.gestures = gestures ?? new Dictionary<Type, GestureRecognizerFactory>(); |
|||
this.behavior = behavior; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly Dictionary<Type, GestureRecognizerFactory> gestures; |
|||
|
|||
public readonly HitTestBehavior? behavior; |
|||
|
|||
public override State createState() { |
|||
return new RawGestureDetectorState(); |
|||
} |
|||
} |
|||
|
|||
public class RawGestureDetectorState : State<RawGestureDetector> { |
|||
Dictionary<Type, GestureRecognizer> _recognizers = new Dictionary<Type, GestureRecognizer>(); |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._syncAll(this.widget.gestures); |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
this._syncAll(this.widget.gestures); |
|||
} |
|||
|
|||
public void replaceGestureRecognizers(Dictionary<Type, GestureRecognizerFactory> gestures) { |
|||
D.assert(() => { |
|||
if (!this.context.findRenderObject().owner.debugDoingLayout) { |
|||
throw new UIWidgetsError( |
|||
"Unexpected call to replaceGestureRecognizers() method of RawGestureDetectorState.\n" + |
|||
"The replaceGestureRecognizers() method can only be called during the layout phase. " + |
|||
"To set the gesture recognizers at other times, trigger a new build using setState() " + |
|||
"and provide the new gesture recognizers as constructor arguments to the corresponding " + |
|||
"RawGestureDetector or GestureDetector object."); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
this._syncAll(gestures); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
foreach (GestureRecognizer recognizer in this._recognizers.Values) { |
|||
recognizer.dispose(); |
|||
} |
|||
|
|||
this._recognizers = null; |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _syncAll(Dictionary<Type, GestureRecognizerFactory> gestures) { |
|||
D.assert(this._recognizers != null); |
|||
var oldRecognizers = this._recognizers; |
|||
this._recognizers = new Dictionary<Type, GestureRecognizer>(); |
|||
|
|||
foreach (Type type in gestures.Keys) { |
|||
D.assert(gestures[type] != null); |
|||
D.assert(gestures[type]._debugAssertTypeMatches(type)); |
|||
D.assert(!this._recognizers.ContainsKey(type)); |
|||
this._recognizers[type] = oldRecognizers.ContainsKey(type) ? oldRecognizers[type] : gestures[type].constructorRaw(); |
|||
D.assert(this._recognizers[type].GetType() == type, |
|||
"GestureRecognizerFactory of type " + type + " created a GestureRecognizer of type " + |
|||
this._recognizers[type].GetType() + |
|||
". The GestureRecognizerFactory must be specialized with the type of the class that it returns from its constructor method."); |
|||
gestures[type].initializerRaw(this._recognizers[type]); |
|||
} |
|||
|
|||
foreach (Type type in oldRecognizers.Keys) { |
|||
if (!this._recognizers.ContainsKey(type)) { |
|||
oldRecognizers[type].dispose(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _handlePointerDown(PointerDownEvent evt) { |
|||
D.assert(this._recognizers != null); |
|||
foreach (GestureRecognizer recognizer in this._recognizers.Values) { |
|||
recognizer.addPointer(evt); |
|||
} |
|||
} |
|||
|
|||
HitTestBehavior _defaultBehavior { |
|||
get { return this.widget.child == null ? HitTestBehavior.translucent : HitTestBehavior.deferToChild; } |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Widget result = new Listener( |
|||
onPointerDown: this._handlePointerDown, |
|||
behavior: this.widget.behavior ?? this._defaultBehavior, |
|||
child: this.widget.child |
|||
); |
|||
return result; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
if (this._recognizers == null) { |
|||
properties.add(DiagnosticsNode.message("DISPOSED")); |
|||
} else { |
|||
List<String> gestures = this._recognizers.Values.Select(recognizer => recognizer.debugDescription) |
|||
.ToList(); |
|||
properties.add(new EnumerableProperty<string>("gestures", gestures, ifEmpty: "<none>")); |
|||
properties.add(new EnumerableProperty<GestureRecognizer>("recognizers", this._recognizers.Values, |
|||
level: DiagnosticLevel.fine)); |
|||
} |
|||
|
|||
properties.add(new EnumProperty<HitTestBehavior?>("behavior", this.widget.behavior, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c9c16577359d413ab2306df2227987dd |
|||
timeCreated: 1537165902 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public interface PageStorageKey { |
|||
} |
|||
|
|||
public class PageStorageKey<T> : ValueKey<T>, PageStorageKey { |
|||
public PageStorageKey(T value) : base(value) { |
|||
} |
|||
} |
|||
|
|||
class _StorageEntryIdentifier : IEquatable<_StorageEntryIdentifier> { |
|||
internal _StorageEntryIdentifier(List<PageStorageKey> keys) { |
|||
D.assert(keys != null); |
|||
this.keys = keys; |
|||
} |
|||
|
|||
public readonly List<PageStorageKey> keys; |
|||
|
|||
public bool isNotEmpty { |
|||
get { return this.keys.isNotEmpty(); } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("StorageEntryIdentifier({0})", |
|||
string.Join(":", this.keys.Select(x => x.ToString()).ToArray())); |
|||
} |
|||
|
|||
public bool Equals(_StorageEntryIdentifier other) { |
|||
if (object.ReferenceEquals(null, other)) return false; |
|||
if (object.ReferenceEquals(this, other)) return true; |
|||
return this.keys.SequenceEqual(other.keys); |
|||
} |
|||
|
|||
public override bool Equals(object obj) { |
|||
if (object.ReferenceEquals(null, obj)) return false; |
|||
if (object.ReferenceEquals(this, obj)) return true; |
|||
if (obj.GetType() != this.GetType()) return false; |
|||
return this.Equals((_StorageEntryIdentifier) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
if (this.keys == null || this.keys.isEmpty()) { |
|||
return 0; |
|||
} |
|||
|
|||
var hashCode = this.keys[0].GetHashCode(); |
|||
for (var i = 1; i < this.keys.Count; i++) { |
|||
hashCode = (hashCode * 397) ^ this.keys[i].GetHashCode(); |
|||
} |
|||
|
|||
return hashCode; |
|||
} |
|||
|
|||
public static bool operator ==(_StorageEntryIdentifier left, _StorageEntryIdentifier right) { |
|||
return object.Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(_StorageEntryIdentifier left, _StorageEntryIdentifier right) { |
|||
return !object.Equals(left, right); |
|||
} |
|||
} |
|||
|
|||
public class PageStorageBucket { |
|||
static bool _maybeAddKey(BuildContext context, List<PageStorageKey> keys) { |
|||
Widget widget = context.widget; |
|||
Key key = widget.key; |
|||
if (key is PageStorageKey) { |
|||
keys.Add((PageStorageKey) key); |
|||
} |
|||
|
|||
return !(widget is PageStorage); |
|||
} |
|||
|
|||
List<PageStorageKey> _allKeys(BuildContext context) { |
|||
List<PageStorageKey> keys = new List<PageStorageKey>(); |
|||
if (_maybeAddKey(context, keys)) { |
|||
context.visitAncestorElements(element => _maybeAddKey(element, keys)); |
|||
} |
|||
|
|||
return keys; |
|||
} |
|||
|
|||
_StorageEntryIdentifier _computeIdentifier(BuildContext context) { |
|||
return new _StorageEntryIdentifier(this._allKeys(context)); |
|||
} |
|||
|
|||
Dictionary<object, object> _storage; |
|||
|
|||
public void writeState(BuildContext context, object data, object identifier = null) { |
|||
this._storage = this._storage ?? new Dictionary<object, object>(); |
|||
if (identifier != null) { |
|||
this._storage[identifier] = data; |
|||
} else { |
|||
_StorageEntryIdentifier contextIdentifier = this._computeIdentifier(context); |
|||
if (contextIdentifier.isNotEmpty) { |
|||
this._storage[contextIdentifier] = data; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public object readState(BuildContext context, object identifier = null) { |
|||
if (this._storage == null) { |
|||
return null; |
|||
} |
|||
|
|||
if (identifier != null) { |
|||
return this._storage[identifier]; |
|||
} |
|||
|
|||
_StorageEntryIdentifier contextIdentifier = this._computeIdentifier(context); |
|||
return contextIdentifier.isNotEmpty ? this._storage[contextIdentifier] : null; |
|||
} |
|||
} |
|||
|
|||
|
|||
public class PageStorage : StatelessWidget { |
|||
public PageStorage( |
|||
Key key, |
|||
PageStorageBucket bucket, |
|||
Widget child |
|||
) : base(key: key) { |
|||
D.assert(bucket != null); |
|||
this.bucket = bucket; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly PageStorageBucket bucket; |
|||
|
|||
public static PageStorageBucket of(BuildContext context) { |
|||
PageStorage widget = (PageStorage) context.ancestorWidgetOfExactType(typeof(PageStorage)); |
|||
return widget == null ? null : widget.bucket; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return this.child; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 45b0579fc707492f9c779c21360b8881 |
|||
timeCreated: 1537153497 |
|
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class PrimaryScrollController : InheritedWidget { |
|||
public PrimaryScrollController( |
|||
Key key = null, |
|||
ScrollController controller = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
D.assert(controller != null); |
|||
this.controller = controller; |
|||
} |
|||
|
|||
private PrimaryScrollController( |
|||
Key key = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
} |
|||
|
|||
public static PrimaryScrollController none( |
|||
Key key = null, |
|||
Widget child = null |
|||
) { |
|||
return new PrimaryScrollController(key, child); |
|||
} |
|||
|
|||
public readonly ScrollController controller; |
|||
|
|||
public static ScrollController of(BuildContext context) { |
|||
PrimaryScrollController result = |
|||
(PrimaryScrollController) context.inheritFromWidgetOfExactType(typeof(PrimaryScrollController)); |
|||
return result == null ? null : result.controller; |
|||
} |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) { |
|||
return this.controller != ((PrimaryScrollController) oldWidget).controller; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<ScrollController>("controller", this.controller, |
|||
ifNull: "no controller", showName: false)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: aaa3c6886fef4a7b80059bd64b818145 |
|||
timeCreated: 1537172309 |
|
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class ScrollBehavior { |
|||
public Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) { |
|||
return child; |
|||
} |
|||
|
|||
public ScrollPhysics getScrollPhysics(BuildContext context) { |
|||
return new BouncingScrollPhysics(); |
|||
} |
|||
|
|||
public virtual bool shouldNotify(ScrollBehavior oldDelegate) { |
|||
return false; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.GetType().ToString(); |
|||
} |
|||
} |
|||
|
|||
public class ScrollConfiguration : InheritedWidget { |
|||
public ScrollConfiguration( |
|||
Key key = null, |
|||
ScrollBehavior behavior = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
D.assert(behavior != null); |
|||
this.behavior = behavior; |
|||
} |
|||
|
|||
public readonly ScrollBehavior behavior; |
|||
|
|||
public static ScrollBehavior of(BuildContext context) { |
|||
ScrollConfiguration configuration = |
|||
(ScrollConfiguration) context.inheritFromWidgetOfExactType(typeof(ScrollConfiguration)); |
|||
if (configuration != null) { |
|||
return configuration.behavior; |
|||
} |
|||
|
|||
return new ScrollBehavior(); |
|||
} |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidgetRaw) { |
|||
var oldWidget = (ScrollConfiguration) oldWidgetRaw; |
|||
|
|||
D.assert(this.behavior != null); |
|||
return this.behavior.GetType() != oldWidget.behavior.GetType() |
|||
|| this.behavior != oldWidget.behavior && this.behavior.shouldNotify(oldWidget.behavior); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<ScrollBehavior>("behavior", this.behavior)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 64f86fe6ce0a475fa47b21a73a250752 |
|||
timeCreated: 1537163722 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using RSG; |
|||
using UIWidgets.animation; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class ScrollController : ChangeNotifier { |
|||
public ScrollController( |
|||
double initialScrollOffset = 0.0, |
|||
bool keepScrollOffset = true, |
|||
string debugLabel = null |
|||
) { |
|||
this._initialScrollOffset = initialScrollOffset; |
|||
this.keepScrollOffset = keepScrollOffset; |
|||
this.debugLabel = debugLabel; |
|||
} |
|||
|
|||
public virtual double initialScrollOffset { |
|||
get { return this._initialScrollOffset; } |
|||
} |
|||
|
|||
readonly double _initialScrollOffset; |
|||
|
|||
public readonly bool keepScrollOffset; |
|||
|
|||
public readonly string debugLabel; |
|||
|
|||
public IEnumerable<ScrollPosition> positions { |
|||
get { return this._positions; } |
|||
} |
|||
|
|||
readonly List<ScrollPosition> _positions = new List<ScrollPosition>(); |
|||
|
|||
public bool hasClients { |
|||
get { return this._positions.isNotEmpty(); } |
|||
} |
|||
|
|||
public ScrollPosition position { |
|||
get { |
|||
D.assert(this._positions.isNotEmpty(), "ScrollController not attached to any scroll views."); |
|||
D.assert(this._positions.Count == 1, "ScrollController attached to multiple scroll views."); |
|||
return this._positions.Single(); |
|||
} |
|||
} |
|||
|
|||
public double offset { |
|||
get { return this.position.pixels; } |
|||
} |
|||
|
|||
|
|||
public IPromise animateTo(double to, |
|||
TimeSpan duration, |
|||
Curve curve |
|||
) { |
|||
D.assert(this._positions.isNotEmpty(), "ScrollController not attached to any scroll views."); |
|||
List<IPromise> animations = new List<IPromise>(this._positions.Count); |
|||
for (int i = 0; i < this._positions.Count; i += 1) { |
|||
animations[i] = this._positions[i].animateTo(to, duration: duration, curve: curve); |
|||
} |
|||
|
|||
return Promise.All(animations); |
|||
} |
|||
|
|||
public void jumpTo(double value) { |
|||
D.assert(this._positions.isNotEmpty(), "ScrollController not attached to any scroll views."); |
|||
foreach (ScrollPosition position in new List<ScrollPosition>(this._positions)) { |
|||
position.jumpTo(value); |
|||
} |
|||
} |
|||
|
|||
public virtual void attach(ScrollPosition position) { |
|||
D.assert(!this._positions.Contains(position)); |
|||
this._positions.Add(position); |
|||
position.addListener(this.notifyListeners); |
|||
} |
|||
|
|||
public virtual void detach(ScrollPosition position) { |
|||
D.assert(this._positions.Contains(position)); |
|||
position.removeListener(this.notifyListeners); |
|||
this._positions.Remove(position); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
foreach (ScrollPosition position in this._positions) { |
|||
position.removeListener(this.notifyListeners); |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
public ScrollPosition createScrollPosition( |
|||
ScrollPhysics physics, |
|||
ScrollContext context, |
|||
ScrollPosition oldPosition |
|||
) { |
|||
return new ScrollPositionWithSingleContext( |
|||
physics: physics, |
|||
context: context, |
|||
initialPixels: this.initialScrollOffset, |
|||
keepScrollOffset: this.keepScrollOffset, |
|||
oldPosition: oldPosition, |
|||
debugLabel: this.debugLabel |
|||
); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
List<string> description = new List<string>(); |
|||
this.debugFillDescription(description); |
|||
return string.Format("{0}({1})", Diagnostics.describeIdentity(this), |
|||
string.Join(", ", description.ToArray())); |
|||
} |
|||
|
|||
protected virtual void debugFillDescription(List<string> description) { |
|||
if (this.debugLabel != null) { |
|||
description.Add(this.debugLabel); |
|||
} |
|||
|
|||
if (this.initialScrollOffset != 0.0) { |
|||
description.Add(string.Format("initialScrollOffset: {0:F1}, ", this.initialScrollOffset)); |
|||
} |
|||
|
|||
if (this._positions.isEmpty()) { |
|||
description.Add("no clients"); |
|||
} else if (this._positions.Count == 1) { |
|||
description.Add(string.Format("one client, offset {0:F1}", this.offset)); |
|||
} else { |
|||
description.Add(this._positions.Count + " clients"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class TrackingScrollController : ScrollController { |
|||
public TrackingScrollController( |
|||
double initialScrollOffset = 0.0, |
|||
bool keepScrollOffset = true, |
|||
String debugLabel = null |
|||
) : base(initialScrollOffset: initialScrollOffset, |
|||
keepScrollOffset: keepScrollOffset, |
|||
debugLabel: debugLabel) { |
|||
} |
|||
|
|||
readonly Dictionary<ScrollPosition, VoidCallback> _positionToListener = |
|||
new Dictionary<ScrollPosition, VoidCallback>(); |
|||
|
|||
ScrollPosition _lastUpdated; |
|||
double? _lastUpdatedOffset; |
|||
|
|||
public ScrollPosition mostRecentlyUpdatedPosition { |
|||
get { return this._lastUpdated; } |
|||
} |
|||
|
|||
public override double initialScrollOffset { |
|||
get { return this._lastUpdatedOffset ?? base.initialScrollOffset; } |
|||
} |
|||
|
|||
public override void attach(ScrollPosition position) { |
|||
base.attach(position); |
|||
D.assert(!this._positionToListener.ContainsKey(position)); |
|||
this._positionToListener[position] = () => { |
|||
this._lastUpdated = position; |
|||
this._lastUpdatedOffset = position.pixels; |
|||
}; |
|||
position.addListener(this._positionToListener[position]); |
|||
} |
|||
|
|||
public override void detach(ScrollPosition position) { |
|||
base.detach(position); |
|||
D.assert(this._positionToListener.ContainsKey(position)); |
|||
position.removeListener(this._positionToListener[position]); |
|||
this._positionToListener.Remove(position); |
|||
if (this._lastUpdated == position) { |
|||
this._lastUpdated = null; |
|||
} |
|||
|
|||
if (this._positionToListener.isEmpty()) { |
|||
this._lastUpdatedOffset = null; |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
foreach (ScrollPosition position in this.positions) { |
|||
D.assert(this._positionToListener.ContainsKey(position)); |
|||
position.removeListener(this._positionToListener[position]); |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 1ae725e691fc4453b2fe1a0e5d40c642 |
|||
timeCreated: 1537160307 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using RSG; |
|||
using UIWidgets.animation; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.physics; |
|||
using UIWidgets.rendering; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class ScrollPositionWithSingleContext : ScrollPosition, ScrollActivityDelegate { |
|||
public ScrollPositionWithSingleContext( |
|||
ScrollPhysics physics = null, |
|||
ScrollContext context = null, |
|||
double? initialPixels = 0.0, |
|||
bool keepScrollOffset = true, |
|||
ScrollPosition oldPosition = null, |
|||
string debugLabel = null |
|||
) : base( |
|||
physics: physics, |
|||
context: context, |
|||
keepScrollOffset: keepScrollOffset, |
|||
oldPosition: oldPosition, |
|||
debugLabel: debugLabel |
|||
) { |
|||
if (this._pixels == null && initialPixels != null) { |
|||
this.correctPixels(initialPixels.Value); |
|||
} |
|||
|
|||
if (this.activity == null) { |
|||
this.goIdle(); |
|||
} |
|||
|
|||
D.assert(this.activity != null); |
|||
} |
|||
|
|||
|
|||
double _heldPreviousVelocity = 0.0; |
|||
|
|||
public override AxisDirection axisDirection { |
|||
get { return this.context.axisDirection; } |
|||
} |
|||
|
|||
public override double setPixels(double newPixels) { |
|||
D.assert(this.activity.isScrolling); |
|||
return base.setPixels(newPixels); |
|||
} |
|||
|
|||
protected override void absorb(ScrollPosition other) { |
|||
base.absorb(other); |
|||
if (!(other is ScrollPositionWithSingleContext)) { |
|||
this.goIdle(); |
|||
return; |
|||
} |
|||
|
|||
this.activity.updateDelegate(this); |
|||
ScrollPositionWithSingleContext typedOther = (ScrollPositionWithSingleContext) other; |
|||
this._userScrollDirection = typedOther._userScrollDirection; |
|||
D.assert(this._currentDrag == null); |
|||
if (typedOther._currentDrag != null) { |
|||
this._currentDrag = typedOther._currentDrag; |
|||
this._currentDrag.updateDelegate(this); |
|||
typedOther._currentDrag = null; |
|||
} |
|||
} |
|||
|
|||
protected override void applyNewDimensions() { |
|||
base.applyNewDimensions(); |
|||
this.context.setCanDrag(this.physics.shouldAcceptUserOffset(this)); |
|||
} |
|||
|
|||
public override void beginActivity(ScrollActivity newActivity) { |
|||
this._heldPreviousVelocity = 0.0; |
|||
if (newActivity == null) { |
|||
return; |
|||
} |
|||
|
|||
D.assert(newActivity.del == this); |
|||
base.beginActivity(newActivity); |
|||
if (this._currentDrag != null) { |
|||
this._currentDrag.dispose(); |
|||
this._currentDrag = null; |
|||
} |
|||
|
|||
if (!this.activity.isScrolling) { |
|||
this.updateUserScrollDirection(ScrollDirection.idle); |
|||
} |
|||
} |
|||
|
|||
public virtual void applyUserOffset(double delta) { |
|||
this.updateUserScrollDirection(delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse); |
|||
this.setPixels(this.pixels - this.physics.applyPhysicsToUserOffset(this, delta)); |
|||
} |
|||
|
|||
public void goIdle() { |
|||
this.beginActivity(new IdleScrollActivity(this)); |
|||
} |
|||
|
|||
public void goBallistic(double velocity) { |
|||
D.assert(this._pixels != null); |
|||
Simulation simulation = this.physics.createBallisticSimulation(this, velocity); |
|||
if (simulation != null) { |
|||
this.beginActivity(new BallisticScrollActivity(this, simulation, this.context.vsync)); |
|||
} else { |
|||
this.goIdle(); |
|||
} |
|||
} |
|||
|
|||
public override ScrollDirection userScrollDirection { |
|||
get { return this._userScrollDirection; } |
|||
} |
|||
|
|||
ScrollDirection _userScrollDirection = ScrollDirection.idle; |
|||
|
|||
protected void updateUserScrollDirection(ScrollDirection value) { |
|||
if (this.userScrollDirection == value) { |
|||
return; |
|||
} |
|||
|
|||
this._userScrollDirection = value; |
|||
this.didUpdateScrollDirection(value); |
|||
} |
|||
|
|||
public override IPromise animateTo(double to, |
|||
TimeSpan duration, |
|||
Curve curve |
|||
) { |
|||
if (PhysicsUtils.nearEqual(to, this.pixels, this.physics.tolerance.distance)) { |
|||
this.jumpTo(to); |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
DrivenScrollActivity activity = new DrivenScrollActivity( |
|||
this, |
|||
from: this.pixels, |
|||
to: to, |
|||
duration: duration, |
|||
curve: curve, |
|||
vsync: this.context.vsync |
|||
); |
|||
this.beginActivity(activity); |
|||
return activity.done; |
|||
} |
|||
|
|||
public override void jumpTo(double value) { |
|||
this.goIdle(); |
|||
if (this.pixels != value) { |
|||
double oldPixels = this.pixels; |
|||
this.forcePixels(value); |
|||
// this.notifyListeners(); already in forcePixels, no need here.
|
|||
this.didStartScroll(); |
|||
this.didUpdateScrollPositionBy(this.pixels - oldPixels); |
|||
this.didEndScroll(); |
|||
} |
|||
|
|||
this.goBallistic(0.0); |
|||
} |
|||
|
|||
public override ScrollHoldController hold(VoidCallback holdCancelCallback) { |
|||
double previousVelocity = this.activity.velocity; |
|||
HoldScrollActivity holdActivity = new HoldScrollActivity( |
|||
del: this, |
|||
onHoldCanceled: holdCancelCallback |
|||
); |
|||
this.beginActivity(holdActivity); |
|||
this._heldPreviousVelocity = previousVelocity; |
|||
return holdActivity; |
|||
} |
|||
|
|||
ScrollDragController _currentDrag; |
|||
|
|||
public override Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) { |
|||
ScrollDragController drag = new ScrollDragController( |
|||
del: this, |
|||
details: details, |
|||
onDragCanceled: dragCancelCallback, |
|||
carriedVelocity: this.physics.carriedMomentum(this._heldPreviousVelocity), |
|||
motionStartDistanceThreshold: this.physics.dragStartDistanceMotionThreshold |
|||
); |
|||
this.beginActivity(new DragScrollActivity(this, drag)); |
|||
D.assert(this._currentDrag == null); |
|||
this._currentDrag = drag; |
|||
return drag; |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this._currentDrag != null) { |
|||
this._currentDrag.dispose(); |
|||
this._currentDrag = null; |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
protected override void debugFillDescription(List<String> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(this.context.GetType().ToString()); |
|||
description.Add(this.physics.ToString()); |
|||
description.Add(this.activity.ToString()); |
|||
description.Add(this.userScrollDirection.ToString()); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 9379d18fbd274c9b834f6d440e39959d |
|||
timeCreated: 1537159068 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public abstract class ScrollView : StatelessWidget { |
|||
protected ScrollView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
double? cacheExtent = null |
|||
) : base(key: key) { |
|||
D.assert(!(controller != null && primary == true), |
|||
"Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. " + |
|||
"You cannot both set primary to true and pass an explicit controller."); |
|||
|
|||
primary = primary ?? controller == null && scrollDirection == Axis.vertical; |
|||
physics = physics ?? (primary.Value ? new AlwaysScrollableScrollPhysics() : null); |
|||
|
|||
this.scrollDirection = scrollDirection; |
|||
this.reverse = reverse; |
|||
this.controller = controller; |
|||
this.primary = primary.Value; |
|||
this.physics = physics; |
|||
this.shrinkWrap = shrinkWrap; |
|||
this.cacheExtent = cacheExtent; |
|||
} |
|||
|
|||
public readonly Axis scrollDirection; |
|||
public readonly bool reverse; |
|||
public readonly ScrollController controller; |
|||
public readonly bool primary; |
|||
public readonly ScrollPhysics physics; |
|||
public readonly bool shrinkWrap; |
|||
public readonly double? cacheExtent; |
|||
|
|||
protected AxisDirection getDirection(BuildContext context) { |
|||
return AxisUtils.getAxisDirectionFromAxisReverseAndDirectionality( |
|||
context, this.scrollDirection, this.reverse); |
|||
} |
|||
|
|||
protected abstract List<Widget> buildSlivers(BuildContext context); |
|||
|
|||
protected Widget buildViewport( |
|||
BuildContext context, |
|||
ViewportOffset offset, |
|||
AxisDirection axisDirection, |
|||
List<Widget> slivers |
|||
) { |
|||
if (this.shrinkWrap) { |
|||
return new ShrinkWrappingViewport( |
|||
axisDirection: axisDirection, |
|||
offset: offset, |
|||
slivers: slivers |
|||
); |
|||
} |
|||
|
|||
return new Viewport( |
|||
axisDirection: axisDirection, |
|||
offset: offset, |
|||
slivers: slivers, |
|||
cacheExtent: this.cacheExtent |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<Widget> slivers = this.buildSlivers(context); |
|||
AxisDirection axisDirection = this.getDirection(context); |
|||
|
|||
ScrollController scrollController = this.primary ? PrimaryScrollController.of(context) : this.controller; |
|||
|
|||
Scrollable scrollable = new Scrollable( |
|||
axisDirection: axisDirection, |
|||
controller: scrollController, |
|||
physics: this.physics, |
|||
viewportBuilder: (viewportContext, offset) => |
|||
this.buildViewport(viewportContext, offset, axisDirection, slivers) |
|||
); |
|||
return this.primary && scrollController != null |
|||
? (Widget) PrimaryScrollController.none(child: scrollable) |
|||
: scrollable; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<Axis>("scrollDirection", this.scrollDirection)); |
|||
properties.add(new FlagProperty("reverse", value: this.reverse, ifTrue: "reversed", showName: true)); |
|||
properties.add(new DiagnosticsProperty<ScrollController>("controller", this.controller, showName: false, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
properties.add(new FlagProperty("primary", value: this.primary, ifTrue: "using primary controller", |
|||
showName: true)); |
|||
properties.add(new DiagnosticsProperty<ScrollPhysics>("physics", this.physics, showName: false, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
properties.add(new FlagProperty("shrinkWrap", value: this.shrinkWrap, ifTrue: "shrink-wrapping", |
|||
showName: true)); |
|||
} |
|||
} |
|||
|
|||
public class CustomScrollView : ScrollView { |
|||
public CustomScrollView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
double? cacheExtent = null, |
|||
List<Widget> slivers = null |
|||
) : base( |
|||
key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
this.slivers = slivers ?? new List<Widget>(); |
|||
} |
|||
|
|||
public readonly List<Widget> slivers; |
|||
|
|||
protected override List<Widget> buildSlivers(BuildContext context) { |
|||
return this.slivers; |
|||
} |
|||
} |
|||
|
|||
public abstract class BoxScrollView : ScrollView { |
|||
public BoxScrollView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? cacheExtent = null |
|||
) : base( |
|||
key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
this.padding = padding; |
|||
} |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
protected override List<Widget> buildSlivers(BuildContext context) { |
|||
Widget sliver = this.buildChildLayout(context); |
|||
|
|||
EdgeInsets effectivePadding = this.padding; // no need to check MediaQuery for now.
|
|||
if (effectivePadding != null) { |
|||
sliver = new SliverPadding(padding: effectivePadding, sliver: sliver); |
|||
} |
|||
|
|||
return new List<Widget> {sliver}; |
|||
} |
|||
|
|||
protected abstract Widget buildChildLayout(BuildContext context); |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<EdgeInsets>("padding", this.padding, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
} |
|||
} |
|||
|
|||
public class ListView : BoxScrollView { |
|||
public ListView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? itemExtent = null, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true, |
|||
double? cacheExtent = null, |
|||
List<Widget> children = null |
|||
) : base( |
|||
key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
padding: padding, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
this.itemExtent = itemExtent; |
|||
this.childrenDelegate = new SliverChildListDelegate( |
|||
children, |
|||
addAutomaticKeepAlives: addAutomaticKeepAlives, |
|||
addRepaintBoundaries: addRepaintBoundaries |
|||
); |
|||
} |
|||
|
|||
private ListView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? itemExtent = null, |
|||
IndexedWidgetBuilder itemBuilder = null, |
|||
int? itemCount = null, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true, |
|||
double? cacheExtent = null |
|||
) : base(key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
padding: padding, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
this.itemExtent = itemExtent; |
|||
this.childrenDelegate = new SliverChildBuilderDelegate( |
|||
itemBuilder, |
|||
childCount: itemCount, |
|||
addAutomaticKeepAlives: addAutomaticKeepAlives, |
|||
addRepaintBoundaries: addRepaintBoundaries |
|||
); |
|||
} |
|||
|
|||
public static ListView builder( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? itemExtent = null, |
|||
IndexedWidgetBuilder itemBuilder = null, |
|||
int? itemCount = null, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true, |
|||
double? cacheExtent = null |
|||
) { |
|||
return new ListView( |
|||
key, |
|||
scrollDirection, |
|||
reverse, |
|||
controller, |
|||
primary, |
|||
physics, |
|||
shrinkWrap, |
|||
padding, |
|||
itemExtent, |
|||
itemBuilder, |
|||
itemCount, |
|||
addAutomaticKeepAlives, |
|||
addRepaintBoundaries |
|||
); |
|||
} |
|||
|
|||
|
|||
private ListView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
IndexedWidgetBuilder itemBuilder = null, |
|||
IndexedWidgetBuilder separatorBuilder = null, |
|||
int itemCount = 0, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true, |
|||
double? cacheExtent = null |
|||
) : base( |
|||
key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
padding: padding, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
D.assert(itemBuilder != null); |
|||
D.assert(separatorBuilder != null); |
|||
D.assert(itemCount >= 0); |
|||
this.itemExtent = null; |
|||
this.childrenDelegate = new SliverChildBuilderDelegate( |
|||
(context, index) => { |
|||
int itemIndex = index / 2; |
|||
return index % 2 == 0 |
|||
? itemBuilder(context, itemIndex) |
|||
: separatorBuilder(context, itemIndex); |
|||
}, |
|||
childCount: Math.Max(0, itemCount * 2 - 1), |
|||
addAutomaticKeepAlives: addAutomaticKeepAlives, |
|||
addRepaintBoundaries: addRepaintBoundaries |
|||
); |
|||
} |
|||
|
|||
public static ListView seperated( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
IndexedWidgetBuilder itemBuilder = null, |
|||
IndexedWidgetBuilder separatorBuilder = null, |
|||
int itemCount = 0, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true, |
|||
double? cacheExtent = null |
|||
) { |
|||
return new ListView( |
|||
key, |
|||
scrollDirection, |
|||
reverse, |
|||
controller, |
|||
primary, |
|||
physics, |
|||
shrinkWrap, |
|||
padding, |
|||
itemBuilder, |
|||
separatorBuilder, |
|||
itemCount, |
|||
addAutomaticKeepAlives, |
|||
addRepaintBoundaries, |
|||
cacheExtent |
|||
); |
|||
} |
|||
|
|||
private ListView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? itemExtent = null, |
|||
SliverChildDelegate childrenDelegate = null, |
|||
double? cacheExtent = null |
|||
) : base( |
|||
key: key, |
|||
scrollDirection: scrollDirection, |
|||
reverse: reverse, |
|||
controller: controller, |
|||
primary: primary, |
|||
physics: physics, |
|||
shrinkWrap: shrinkWrap, |
|||
padding: padding, |
|||
cacheExtent: cacheExtent |
|||
) { |
|||
D.assert(childrenDelegate != null); |
|||
this.itemExtent = itemExtent; |
|||
this.childrenDelegate = childrenDelegate; |
|||
} |
|||
|
|||
public static ListView custom( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
ScrollController controller = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
bool shrinkWrap = false, |
|||
EdgeInsets padding = null, |
|||
double? itemExtent = null, |
|||
SliverChildDelegate childrenDelegate = null, |
|||
double? cacheExtent = null |
|||
) { |
|||
return new ListView( |
|||
key, |
|||
scrollDirection, |
|||
reverse, |
|||
controller, |
|||
primary, |
|||
physics, |
|||
shrinkWrap, |
|||
padding, |
|||
itemExtent, |
|||
childrenDelegate, |
|||
cacheExtent); |
|||
} |
|||
|
|||
public readonly double? itemExtent; |
|||
|
|||
public readonly SliverChildDelegate childrenDelegate; |
|||
|
|||
protected override Widget buildChildLayout(BuildContext context) { |
|||
if (this.itemExtent != null) { |
|||
return new SliverFixedExtentList( |
|||
del: this.childrenDelegate, |
|||
itemExtent: this.itemExtent.Value |
|||
); |
|||
} |
|||
|
|||
return new SliverList(del: this.childrenDelegate); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DoubleProperty("itemExtent", this.itemExtent, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 167b885cf5254b048c2bac3acf71aafa |
|||
timeCreated: 1537171143 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using RSG; |
|||
using UIWidgets.animation; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.rendering; |
|||
using UIWidgets.scheduler; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public delegate Widget ViewportBuilder(BuildContext context, ViewportOffset position); |
|||
|
|||
public class Scrollable : StatefulWidget { |
|||
public Scrollable( |
|||
Key key = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
ScrollController controller = null, |
|||
ScrollPhysics physics = null, |
|||
ViewportBuilder viewportBuilder = null |
|||
) : base(key: key) { |
|||
D.assert(viewportBuilder != null); |
|||
|
|||
this.axisDirection = axisDirection; |
|||
this.controller = controller; |
|||
this.physics = physics; |
|||
this.viewportBuilder = viewportBuilder; |
|||
} |
|||
|
|||
public readonly AxisDirection axisDirection; |
|||
|
|||
public readonly ScrollController controller; |
|||
|
|||
public readonly ScrollPhysics physics; |
|||
|
|||
public readonly ViewportBuilder viewportBuilder; |
|||
|
|||
public Axis axis { |
|||
get { return AxisUtils.axisDirectionToAxis(this.axisDirection); } |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new ScrollableState(); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<AxisDirection>("axisDirection", this.axisDirection)); |
|||
properties.add(new DiagnosticsProperty<ScrollPhysics>("physics", this.physics)); |
|||
} |
|||
|
|||
public static ScrollableState of(BuildContext context) { |
|||
_ScrollableScope widget = (_ScrollableScope) context.inheritFromWidgetOfExactType(typeof(_ScrollableScope)); |
|||
return widget == null ? null : widget.scrollable; |
|||
} |
|||
|
|||
public static IPromise ensureVisible(BuildContext context, |
|||
double alignment = 0.0, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null |
|||
) { |
|||
duration = duration ?? TimeSpan.Zero; |
|||
curve = curve ?? Curves.ease; |
|||
List<IPromise> futures = new List<IPromise>(); |
|||
|
|||
ScrollableState scrollable = Scrollable.of(context); |
|||
while (scrollable != null) { |
|||
futures.Add(scrollable.position.ensureVisible( |
|||
context.findRenderObject(), |
|||
alignment: alignment, |
|||
duration: duration, |
|||
curve: curve |
|||
)); |
|||
context = scrollable.context; |
|||
scrollable = Scrollable.of(context); |
|||
} |
|||
|
|||
if (futures.isEmpty() || duration == TimeSpan.Zero) { |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
if (futures.Count == 1) { |
|||
return futures.Single(); |
|||
} |
|||
|
|||
return Promise.All(futures); |
|||
} |
|||
} |
|||
|
|||
class _ScrollableScope : InheritedWidget { |
|||
internal _ScrollableScope( |
|||
Key key = null, |
|||
ScrollableState scrollable = null, |
|||
ScrollPosition position = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
D.assert(scrollable != null); |
|||
D.assert(child != null); |
|||
this.scrollable = scrollable; |
|||
this.position = position; |
|||
} |
|||
|
|||
public readonly ScrollableState scrollable; |
|||
|
|||
public readonly ScrollPosition position; |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget old) { |
|||
return this.position != ((_ScrollableScope) old).position; |
|||
} |
|||
} |
|||
|
|||
public class ScrollableState : TickerProviderStateMixin<Scrollable>, ScrollContext { |
|||
public ScrollPosition position { |
|||
get { return this._position; } |
|||
} |
|||
|
|||
ScrollPosition _position; |
|||
|
|||
public AxisDirection axisDirection { |
|||
get { return this.widget.axisDirection; } |
|||
} |
|||
|
|||
ScrollBehavior _configuration; |
|||
|
|||
ScrollPhysics _physics; |
|||
|
|||
void _updatePosition() { |
|||
this._configuration = ScrollConfiguration.of(this.context); |
|||
this._physics = this._configuration.getScrollPhysics(this.context); |
|||
if (this.widget.physics != null) { |
|||
this._physics = this.widget.physics.applyTo(this._physics); |
|||
} |
|||
|
|||
ScrollController controller = this.widget.controller; |
|||
ScrollPosition oldPosition = this.position; |
|||
if (oldPosition != null) { |
|||
if (controller != null) { |
|||
controller.detach(oldPosition); |
|||
} |
|||
|
|||
Window.instance.scheduleMicrotask(oldPosition.dispose); |
|||
} |
|||
|
|||
this._position = controller == null |
|||
? null |
|||
: controller.createScrollPosition(this._physics, this, oldPosition); |
|||
this._position = this._position |
|||
?? new ScrollPositionWithSingleContext(physics: this._physics, context: this, |
|||
oldPosition: oldPosition); |
|||
D.assert(this.position != null); |
|||
if (controller != null) { |
|||
controller.attach(this.position); |
|||
} |
|||
} |
|||
|
|||
public override void didChangeDependencies() { |
|||
base.didChangeDependencies(); |
|||
this._updatePosition(); |
|||
} |
|||
|
|||
bool _shouldUpdatePosition(Scrollable oldWidget) { |
|||
ScrollPhysics newPhysics = this.widget.physics; |
|||
ScrollPhysics oldPhysics = oldWidget.physics; |
|||
do { |
|||
Type newPhysicsType = newPhysics != null ? newPhysics.GetType() : null; |
|||
Type oldPhysicsType = oldPhysics != null ? oldPhysics.GetType() : null; |
|||
|
|||
if (newPhysicsType != oldPhysicsType) { |
|||
return true; |
|||
} |
|||
|
|||
if (newPhysics != null) { |
|||
newPhysics = newPhysics.parent; |
|||
} |
|||
|
|||
if (oldPhysics != null) { |
|||
oldPhysics = oldPhysics.parent; |
|||
} |
|||
} while (newPhysics != null || oldPhysics != null); |
|||
|
|||
Type controllerType = this.widget.controller == null ? null : this.widget.controller.GetType(); |
|||
Type oldControllerType = oldWidget.controller == null ? null : oldWidget.controller.GetType(); |
|||
return controllerType != oldControllerType; |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidgetRaw) { |
|||
Scrollable oldWidget = (Scrollable) oldWidgetRaw; |
|||
base.didUpdateWidget(oldWidget); |
|||
|
|||
if (this.widget.controller != oldWidget.controller) { |
|||
if (oldWidget.controller != null) { |
|||
oldWidget.controller.detach(this.position); |
|||
} |
|||
|
|||
if (this.widget.controller != null) { |
|||
this.widget.controller.attach(this.position); |
|||
} |
|||
} |
|||
|
|||
if (this._shouldUpdatePosition(oldWidget)) { |
|||
this._updatePosition(); |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this.widget.controller != null) { |
|||
this.widget.controller.detach(this.position); |
|||
} |
|||
|
|||
this.position.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
readonly GlobalKey<RawGestureDetectorState> _gestureDetectorKey = GlobalKey<RawGestureDetectorState>.key(); |
|||
readonly GlobalKey _ignorePointerKey = GlobalKey.key(); |
|||
|
|||
Dictionary<Type, GestureRecognizerFactory> _gestureRecognizers = |
|||
new Dictionary<Type, GestureRecognizerFactory>(); |
|||
|
|||
bool _shouldIgnorePointer = false; |
|||
|
|||
bool _lastCanDrag; |
|||
Axis _lastAxisDirection; |
|||
|
|||
public void setCanDrag(bool canDrag) { |
|||
if (canDrag == this._lastCanDrag && (!canDrag || this.widget.axis == this._lastAxisDirection)) { |
|||
return; |
|||
} |
|||
|
|||
if (!canDrag) { |
|||
this._gestureRecognizers = new Dictionary<Type, GestureRecognizerFactory>(); |
|||
} else { |
|||
switch (this.widget.axis) { |
|||
case Axis.vertical: |
|||
this._gestureRecognizers = new Dictionary<Type, GestureRecognizerFactory>(); |
|||
this._gestureRecognizers.Add(typeof(VerticalDragGestureRecognizer), |
|||
new GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>( |
|||
() => new VerticalDragGestureRecognizer(), |
|||
instance => { |
|||
instance.onDown = this._handleDragDown; |
|||
instance.onStart = this._handleDragStart; |
|||
instance.onUpdate = this._handleDragUpdate; |
|||
instance.onEnd = this._handleDragEnd; |
|||
instance.onCancel = this._handleDragCancel; |
|||
instance.minFlingDistance = |
|||
this._physics == null ? (double?) null : this._physics.minFlingDistance; |
|||
instance.minFlingVelocity = |
|||
this._physics == null ? (double?) null : this._physics.minFlingVelocity; |
|||
instance.maxFlingVelocity = |
|||
this._physics == null ? (double?) null : this._physics.maxFlingVelocity; |
|||
} |
|||
)); |
|||
break; |
|||
case Axis.horizontal: |
|||
this._gestureRecognizers = new Dictionary<Type, GestureRecognizerFactory>(); |
|||
this._gestureRecognizers.Add(typeof(HorizontalDragGestureRecognizer), |
|||
new GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>( |
|||
() => new HorizontalDragGestureRecognizer(), |
|||
instance => { |
|||
instance.onDown = this._handleDragDown; |
|||
instance.onStart = this._handleDragStart; |
|||
instance.onUpdate = this._handleDragUpdate; |
|||
instance.onEnd = this._handleDragEnd; |
|||
instance.onCancel = this._handleDragCancel; |
|||
instance.minFlingDistance = |
|||
this._physics == null ? (double?) null : this._physics.minFlingDistance; |
|||
instance.minFlingVelocity = |
|||
this._physics == null ? (double?) null : this._physics.minFlingVelocity; |
|||
instance.maxFlingVelocity = |
|||
this._physics == null ? (double?) null : this._physics.maxFlingVelocity; |
|||
} |
|||
)); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
this._lastCanDrag = canDrag; |
|||
this._lastAxisDirection = this.widget.axis; |
|||
if (this._gestureDetectorKey.currentState != null) { |
|||
this._gestureDetectorKey.currentState.replaceGestureRecognizers(this._gestureRecognizers); |
|||
} |
|||
} |
|||
|
|||
public TickerProvider vsync { |
|||
get { return this; } |
|||
} |
|||
|
|||
public void setIgnorePointer(bool value) { |
|||
if (this._shouldIgnorePointer == value) { |
|||
return; |
|||
} |
|||
|
|||
this._shouldIgnorePointer = value; |
|||
if (this._ignorePointerKey.currentContext != null) { |
|||
var renderBox = (RenderIgnorePointer) this._ignorePointerKey.currentContext.findRenderObject(); |
|||
renderBox.ignoring = this._shouldIgnorePointer; |
|||
} |
|||
} |
|||
|
|||
public BuildContext notificationContext { |
|||
get { return this._gestureDetectorKey.currentContext; } |
|||
} |
|||
|
|||
public BuildContext storageContext { |
|||
get { return this.context; } |
|||
} |
|||
|
|||
Drag _drag; |
|||
|
|||
ScrollHoldController _hold; |
|||
|
|||
void _handleDragDown(DragDownDetails details) { |
|||
D.assert(this._drag == null); |
|||
D.assert(this._hold == null); |
|||
this._hold = this.position.hold(this._disposeHold); |
|||
} |
|||
|
|||
void _handleDragStart(DragStartDetails details) { |
|||
D.assert(this._drag == null); |
|||
this._drag = this.position.drag(details, this._disposeDrag); |
|||
D.assert(this._drag != null); |
|||
D.assert(this._hold == null); |
|||
} |
|||
|
|||
void _handleDragUpdate(DragUpdateDetails details) { |
|||
D.assert(this._hold == null || this._drag == null); |
|||
if (this._drag != null) { |
|||
this._drag.update(details); |
|||
} |
|||
} |
|||
|
|||
void _handleDragEnd(DragEndDetails details) { |
|||
D.assert(this._hold == null || this._drag == null); |
|||
if (this._drag != null) { |
|||
this._drag.end(details); |
|||
} |
|||
|
|||
D.assert(this._drag == null); |
|||
} |
|||
|
|||
void _handleDragCancel() { |
|||
D.assert(this._hold == null || this._drag == null); |
|||
if (this._hold != null) { |
|||
this._hold.cancel(); |
|||
} |
|||
|
|||
if (this._drag != null) { |
|||
this._drag.cancel(); |
|||
} |
|||
|
|||
D.assert(this._hold == null); |
|||
D.assert(this._drag == null); |
|||
} |
|||
|
|||
void _disposeHold() { |
|||
this._hold = null; |
|||
} |
|||
|
|||
void _disposeDrag() { |
|||
this._drag = null; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(this.position != null); |
|||
|
|||
Widget result = new RawGestureDetector( |
|||
key: this._gestureDetectorKey, |
|||
gestures: this._gestureRecognizers, |
|||
behavior: HitTestBehavior.opaque, |
|||
child: new IgnorePointer( |
|||
key: this._ignorePointerKey, |
|||
ignoring: this._shouldIgnorePointer, |
|||
child: new _ScrollableScope( |
|||
scrollable: this, |
|||
position: this.position, |
|||
child: this.widget.viewportBuilder(context, this.position) |
|||
) |
|||
) |
|||
); |
|||
|
|||
return this._configuration.buildViewportChrome(context, result, this.widget.axisDirection); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<ScrollPosition>("position", this.position)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c3917312a54a4263a839cd628ae99010 |
|||
timeCreated: 1537160124 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public abstract class SliverChildDelegate { |
|||
protected SliverChildDelegate() { |
|||
} |
|||
|
|||
public abstract Widget build(BuildContext context, int index); |
|||
|
|||
public virtual int? estimatedChildCount { |
|||
get { return null; } |
|||
} |
|||
|
|||
public virtual double? estimateMaxScrollOffset( |
|||
int firstIndex, |
|||
int lastIndex, |
|||
double leadingScrollOffset, |
|||
double trailingScrollOffset |
|||
) { |
|||
return null; |
|||
} |
|||
|
|||
public virtual void didFinishLayout(int firstIndex, int lastIndex) { |
|||
} |
|||
|
|||
public abstract bool shouldRebuild(SliverChildDelegate oldDelegate); |
|||
|
|||
public override string ToString() { |
|||
var description = new List<string>(); |
|||
this.debugFillDescription(description); |
|||
return string.Format("{0}({1})", Diagnostics.describeIdentity(this), |
|||
string.Join(", ", description.ToArray())); |
|||
} |
|||
|
|||
protected virtual void debugFillDescription(List<String> description) { |
|||
try { |
|||
var children = this.estimatedChildCount; |
|||
if (children != null) { |
|||
description.Add("estimated child count: " + children); |
|||
} |
|||
} |
|||
catch (Exception ex) { |
|||
description.Add("estimated child count: EXCEPTION (" + ex.GetType() + ")"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class SliverChildBuilderDelegate : SliverChildDelegate { |
|||
public SliverChildBuilderDelegate( |
|||
IndexedWidgetBuilder builder, |
|||
int? childCount = null, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true |
|||
) { |
|||
D.assert(builder != null); |
|||
this.builder = build; |
|||
this.childCount = childCount; |
|||
this.addAutomaticKeepAlives = addAutomaticKeepAlives; |
|||
this.addRepaintBoundaries = addRepaintBoundaries; |
|||
} |
|||
|
|||
|
|||
public readonly IndexedWidgetBuilder builder; |
|||
|
|||
public readonly int? childCount; |
|||
|
|||
public readonly bool addAutomaticKeepAlives; |
|||
|
|||
public readonly bool addRepaintBoundaries; |
|||
|
|||
public override Widget build(BuildContext context, int index) { |
|||
D.assert(this.builder != null); |
|||
if (index < 0 || (this.childCount != null && index >= this.childCount)) { |
|||
return null; |
|||
} |
|||
|
|||
Widget child = this.builder(context, index); |
|||
if (child == null) { |
|||
return null; |
|||
} |
|||
|
|||
if (this.addRepaintBoundaries) { |
|||
child = RepaintBoundary.wrap(child, index); |
|||
} |
|||
|
|||
if (this.addAutomaticKeepAlives) { |
|||
child = new AutomaticKeepAlive(child: child); |
|||
} |
|||
|
|||
return child; |
|||
} |
|||
|
|||
public override int? estimatedChildCount { |
|||
get { return this.childCount; } |
|||
} |
|||
|
|||
public override bool shouldRebuild(SliverChildDelegate oldDelegate) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public class SliverChildListDelegate : SliverChildDelegate { |
|||
public SliverChildListDelegate( |
|||
List<Widget> children, |
|||
bool addAutomaticKeepAlives = true, |
|||
bool addRepaintBoundaries = true |
|||
) { |
|||
D.assert(children != null); |
|||
this.children = children; |
|||
this.addAutomaticKeepAlives = addAutomaticKeepAlives; |
|||
this.addRepaintBoundaries = addRepaintBoundaries; |
|||
} |
|||
|
|||
public readonly bool addAutomaticKeepAlives; |
|||
|
|||
public readonly bool addRepaintBoundaries; |
|||
|
|||
public readonly List<Widget> children; |
|||
|
|||
public override Widget build(BuildContext context, int index) { |
|||
D.assert(this.children != null); |
|||
if (index < 0 || index >= this.children.Count) { |
|||
return null; |
|||
} |
|||
|
|||
Widget child = this.children[index]; |
|||
D.assert(child != null); |
|||
if (this.addRepaintBoundaries) { |
|||
child = RepaintBoundary.wrap(child, index); |
|||
} |
|||
|
|||
if (this.addAutomaticKeepAlives) { |
|||
child = new AutomaticKeepAlive(child: child); |
|||
} |
|||
|
|||
return child; |
|||
} |
|||
|
|||
public override int? estimatedChildCount { |
|||
get { return this.children.Count; } |
|||
} |
|||
|
|||
public override bool shouldRebuild(SliverChildDelegate oldDelegate) { |
|||
return this.children != ((SliverChildListDelegate) oldDelegate).children; |
|||
} |
|||
} |
|||
|
|||
public abstract class SliverMultiBoxAdaptorWidget : RenderObjectWidget { |
|||
protected SliverMultiBoxAdaptorWidget( |
|||
Key key = null, |
|||
SliverChildDelegate del = null |
|||
) : base(key: key) { |
|||
D.assert(del != null); |
|||
this.del = del; |
|||
} |
|||
|
|||
public readonly SliverChildDelegate del; |
|||
|
|||
public override Element createElement() { |
|||
return new SliverMultiBoxAdaptorElement(this); |
|||
} |
|||
|
|||
public double? estimateMaxScrollOffset( |
|||
SliverConstraints constraints, |
|||
int firstIndex, |
|||
int lastIndex, |
|||
double leadingScrollOffset, |
|||
double trailingScrollOffset |
|||
) { |
|||
D.assert(lastIndex >= firstIndex); |
|||
return this.del.estimateMaxScrollOffset( |
|||
firstIndex, |
|||
lastIndex, |
|||
leadingScrollOffset, |
|||
trailingScrollOffset |
|||
); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<SliverChildDelegate>("del", this.del)); |
|||
} |
|||
} |
|||
|
|||
public class SliverList : SliverMultiBoxAdaptorWidget { |
|||
public SliverList( |
|||
Key key = null, |
|||
SliverChildDelegate del = null |
|||
) : base(key: key, del: del) { |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
SliverMultiBoxAdaptorElement element = (SliverMultiBoxAdaptorElement) context; |
|||
return new RenderSliverList(childManager: element); |
|||
} |
|||
} |
|||
|
|||
public class SliverFixedExtentList : SliverMultiBoxAdaptorWidget { |
|||
public SliverFixedExtentList( |
|||
Key key = null, |
|||
SliverChildDelegate del = null, |
|||
double itemExtent = 0 |
|||
) : base(key: key, del: del) { |
|||
this.itemExtent = itemExtent; |
|||
} |
|||
|
|||
public readonly double itemExtent; |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
SliverMultiBoxAdaptorElement element = (SliverMultiBoxAdaptorElement) context; |
|||
return new RenderSliverFixedExtentList(childManager: element, itemExtent: this.itemExtent); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObjectRaw) { |
|||
var renderObject = (RenderSliverFixedExtentList) renderObjectRaw; |
|||
renderObject.itemExtent = this.itemExtent; |
|||
} |
|||
} |
|||
|
|||
|
|||
public class SliverMultiBoxAdaptorElement : RenderObjectElement, RenderSliverBoxChildManager { |
|||
public SliverMultiBoxAdaptorElement(SliverMultiBoxAdaptorWidget widget) : base(widget) { |
|||
} |
|||
|
|||
public new SliverMultiBoxAdaptorWidget widget { |
|||
get { return (SliverMultiBoxAdaptorWidget) base.widget; } |
|||
} |
|||
|
|||
public new RenderSliverMultiBoxAdaptor renderObject { |
|||
get { return (RenderSliverMultiBoxAdaptor) base.renderObject; } |
|||
} |
|||
|
|||
public override void update(Widget newWidgetRaw) { |
|||
var newWidget = (SliverMultiBoxAdaptorWidget) newWidgetRaw; |
|||
SliverMultiBoxAdaptorWidget oldWidget = this.widget; |
|||
base.update(newWidget); |
|||
SliverChildDelegate newDelegate = newWidget.del; |
|||
SliverChildDelegate oldDelegate = oldWidget.del; |
|||
if (newDelegate != oldDelegate && |
|||
(newDelegate.GetType() != oldDelegate.GetType() || newDelegate.shouldRebuild(oldDelegate))) { |
|||
this.performRebuild(); |
|||
} |
|||
} |
|||
|
|||
Dictionary<int, Widget> _childWidgets = new Dictionary<int, Widget>(); |
|||
SortedDictionary<int, Element> _childElements = new SortedDictionary<int, Element>(); |
|||
RenderBox _currentBeforeChild; |
|||
|
|||
protected override void performRebuild() { |
|||
this._childWidgets.Clear(); |
|||
base.performRebuild(); |
|||
|
|||
this._currentBeforeChild = null; |
|||
D.assert(this._currentlyUpdatingChildIndex == null); |
|||
try { |
|||
int firstIndex = 0; |
|||
int lastIndex = 0; |
|||
|
|||
if (!this._childElements.isEmpty()) { |
|||
firstIndex = this._childElements.Keys.First(); |
|||
lastIndex = this._childElements.Keys.Last(); |
|||
if (this._didUnderflow) { |
|||
lastIndex += 1; |
|||
} |
|||
} |
|||
|
|||
for (int index = firstIndex; index <= lastIndex; ++index) { |
|||
this._currentlyUpdatingChildIndex = index; |
|||
Element newChild = this.updateChild(this._childElements[index], this._build(index), index); |
|||
if (newChild != null) { |
|||
this._childElements[index] = newChild; |
|||
this._currentBeforeChild = (RenderBox) newChild.renderObject; |
|||
} else { |
|||
this._childElements.Remove(index); |
|||
} |
|||
} |
|||
} |
|||
finally { |
|||
this._currentlyUpdatingChildIndex = null; |
|||
} |
|||
} |
|||
|
|||
Widget _build(int index) { |
|||
return this._childWidgets.putIfAbsent(index, () => this.widget.del.build(this, index)); |
|||
} |
|||
|
|||
public void createChild(int index, RenderBox after = null) { |
|||
D.assert(this._currentlyUpdatingChildIndex == null); |
|||
this.owner.buildScope(this, () => { |
|||
bool insertFirst = after == null; |
|||
D.assert(insertFirst || this._childElements[index - 1] != null); |
|||
this._currentBeforeChild = insertFirst ? null : (RenderBox) this._childElements[index - 1].renderObject; |
|||
Element newChild; |
|||
try { |
|||
this._currentlyUpdatingChildIndex = index; |
|||
newChild = this.updateChild(this._childElements[index], this._build(index), index); |
|||
} |
|||
finally { |
|||
this._currentlyUpdatingChildIndex = null; |
|||
} |
|||
|
|||
if (newChild != null) { |
|||
this._childElements[index] = newChild; |
|||
} else { |
|||
this._childElements.Remove(index); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
protected override Element updateChild(Element child, Widget newWidget, object newSlot) { |
|||
SliverMultiBoxAdaptorParentData oldParentData = null; |
|||
if (child != null && child.renderObject != null) { |
|||
oldParentData = (SliverMultiBoxAdaptorParentData) child.renderObject.parentData; |
|||
} |
|||
|
|||
Element newChild = base.updateChild(child, newWidget, newSlot); |
|||
SliverMultiBoxAdaptorParentData newParentData = null; |
|||
|
|||
if (child != null && child.renderObject != null) { |
|||
newParentData = (SliverMultiBoxAdaptorParentData) newChild.renderObject.parentData; |
|||
} |
|||
|
|||
if (oldParentData != newParentData && oldParentData != null && newParentData != null) { |
|||
newParentData.layoutOffset = oldParentData.layoutOffset; |
|||
} |
|||
|
|||
return newChild; |
|||
} |
|||
|
|||
protected override void forgetChild(Element child) { |
|||
D.assert(child != null); |
|||
D.assert(child.slot != null); |
|||
D.assert(this._childElements.ContainsKey((int) child.slot)); |
|||
this._childElements.Remove((int) child.slot); |
|||
} |
|||
|
|||
public void removeChild(RenderBox child) { |
|||
int index = this.renderObject.indexOf(child); |
|||
D.assert(this._currentlyUpdatingChildIndex == null); |
|||
D.assert(index >= 0); |
|||
this.owner.buildScope(this, () => { |
|||
D.assert(this._childElements.ContainsKey(index)); |
|||
try { |
|||
this._currentlyUpdatingChildIndex = index; |
|||
Element result = this.updateChild(this._childElements[index], null, index); |
|||
D.assert(result == null); |
|||
} |
|||
finally { |
|||
this._currentlyUpdatingChildIndex = null; |
|||
} |
|||
|
|||
this._childElements.Remove(index); |
|||
D.assert(!this._childElements.ContainsKey(index)); |
|||
}); |
|||
} |
|||
|
|||
static double _extrapolateMaxScrollOffset( |
|||
int firstIndex, |
|||
int lastIndex, |
|||
double leadingScrollOffset, |
|||
double trailingScrollOffset, |
|||
int childCount |
|||
) { |
|||
if (lastIndex == childCount - 1) |
|||
return trailingScrollOffset; |
|||
int reifiedCount = lastIndex - firstIndex + 1; |
|||
double averageExtent = (trailingScrollOffset - leadingScrollOffset) / reifiedCount; |
|||
int remainingCount = childCount - lastIndex - 1; |
|||
return trailingScrollOffset + averageExtent * remainingCount; |
|||
} |
|||
|
|||
public double? estimateMaxScrollOffset(SliverConstraints constraints, |
|||
int firstIndex = 0, |
|||
int lastIndex = 0, |
|||
double leadingScrollOffset = 0, |
|||
double trailingScrollOffset = 0 |
|||
) { |
|||
int? childCount = this.childCount; |
|||
if (childCount == null) { |
|||
return double.PositiveInfinity; |
|||
} |
|||
|
|||
return this.widget.estimateMaxScrollOffset( |
|||
constraints, |
|||
firstIndex, |
|||
lastIndex, |
|||
leadingScrollOffset, |
|||
trailingScrollOffset |
|||
) ?? _extrapolateMaxScrollOffset( |
|||
firstIndex, |
|||
lastIndex, |
|||
leadingScrollOffset, |
|||
trailingScrollOffset, |
|||
childCount.Value |
|||
); |
|||
} |
|||
|
|||
public int? childCount { |
|||
get { return this.widget.del.estimatedChildCount; } |
|||
} |
|||
|
|||
public void didStartLayout() { |
|||
D.assert(this.debugAssertChildListLocked()); |
|||
} |
|||
|
|||
public void didFinishLayout() { |
|||
D.assert(this.debugAssertChildListLocked()); |
|||
int firstIndex = this._childElements.Keys.FirstOrDefault(); |
|||
int lastIndex = this._childElements.Keys.LastOrDefault(); |
|||
this.widget.del.didFinishLayout(firstIndex, lastIndex); |
|||
} |
|||
|
|||
int? _currentlyUpdatingChildIndex; |
|||
|
|||
public bool debugAssertChildListLocked() { |
|||
D.assert(this._currentlyUpdatingChildIndex == null); |
|||
return true; |
|||
} |
|||
|
|||
public void didAdoptChild(RenderBox child) { |
|||
D.assert(this._currentlyUpdatingChildIndex != null); |
|||
SliverMultiBoxAdaptorParentData childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
childParentData.index = this._currentlyUpdatingChildIndex.Value; |
|||
} |
|||
|
|||
bool _didUnderflow = false; |
|||
|
|||
public void setDidUnderflow(bool value) { |
|||
this._didUnderflow = value; |
|||
} |
|||
|
|||
protected override void insertChildRenderObject(RenderObject child, object slotRaw) { |
|||
D.assert(slotRaw != null); |
|||
int slot = (int) slotRaw; |
|||
|
|||
D.assert(this._currentlyUpdatingChildIndex == slot); |
|||
D.assert(this.renderObject.debugValidateChild(child)); |
|||
this.renderObject.insert((RenderBox) child, after: this._currentBeforeChild); |
|||
D.assert(() => { |
|||
SliverMultiBoxAdaptorParentData childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
D.assert(slot == childParentData.index); |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
protected override void moveChildRenderObject(RenderObject child, object slotRaw) { |
|||
D.assert(false); |
|||
} |
|||
|
|||
protected override void removeChildRenderObject(RenderObject child) { |
|||
D.assert(this._currentlyUpdatingChildIndex != null); |
|||
this.renderObject.remove((RenderBox) child); |
|||
} |
|||
|
|||
public override void visitChildren(ElementVisitor visitor) { |
|||
D.assert(!this._childElements.Values.Any(child => child == null)); |
|||
this._childElements.Values.ToList().ForEach(e => visitor(e)); |
|||
} |
|||
|
|||
public override void debugVisitOnstageChildren(ElementVisitor visitor) { |
|||
this._childElements.Values.Where(child => { |
|||
SliverMultiBoxAdaptorParentData parentData = |
|||
(SliverMultiBoxAdaptorParentData) child.renderObject.parentData; |
|||
double itemExtent = 0; |
|||
switch (this.renderObject.constraints.axis) { |
|||
case Axis.horizontal: |
|||
itemExtent = child.renderObject.paintBounds.width; |
|||
break; |
|||
case Axis.vertical: |
|||
itemExtent = child.renderObject.paintBounds.height; |
|||
break; |
|||
} |
|||
|
|||
return parentData.layoutOffset < this.renderObject.constraints.scrollOffset + |
|||
this.renderObject.constraints.remainingPaintExtent && |
|||
parentData.layoutOffset + itemExtent > this.renderObject.constraints.scrollOffset; |
|||
}).ToList().ForEach(e => visitor(e)); |
|||
} |
|||
} |
|||
|
|||
public class KeepAlive : ParentDataWidget<SliverMultiBoxAdaptorWidget> { |
|||
public KeepAlive( |
|||
Key key = null, |
|||
bool keepAlive = true, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
D.assert(child != null); |
|||
this.keepAlive = keepAlive; |
|||
} |
|||
|
|||
public readonly bool keepAlive; |
|||
|
|||
public override void applyParentData(RenderObject renderObject) { |
|||
D.assert(renderObject.parentData is SliverMultiBoxAdaptorParentData); |
|||
SliverMultiBoxAdaptorParentData parentData = (SliverMultiBoxAdaptorParentData) renderObject.parentData; |
|||
if (parentData.keepAlive != this.keepAlive) { |
|||
parentData.keepAlive = this.keepAlive; |
|||
var targetParent = renderObject.parent; |
|||
if (targetParent is RenderObject && !this.keepAlive) { |
|||
((RenderObject) targetParent).markNeedsLayout(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override bool debugCanApplyOutOfTurn() { |
|||
return this.keepAlive; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<bool>("keepAlive", this.keepAlive)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 657ce5eaa41b4a498591bbb1682d04f4 |
|||
timeCreated: 1537323273 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class Viewport : MultiChildRenderObjectWidget { |
|||
public Viewport( |
|||
Key key = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
AxisDirection? crossAxisDirection = null, |
|||
double anchor = 0.0, |
|||
ViewportOffset offset = null, |
|||
Key center = null, |
|||
double? cacheExtent = null, |
|||
List<Widget> slivers = null |
|||
) : base(key: key, children: slivers) { |
|||
D.assert(offset != null); |
|||
D.assert(center == null || this.children.Count(child => child.key == center) == 1); |
|||
|
|||
this.axisDirection = axisDirection; |
|||
this.crossAxisDirection = crossAxisDirection; |
|||
this.anchor = anchor; |
|||
this.offset = offset; |
|||
this.center = center; |
|||
this.cacheExtent = cacheExtent; |
|||
} |
|||
|
|||
public readonly AxisDirection axisDirection; |
|||
|
|||
public readonly AxisDirection? crossAxisDirection; |
|||
|
|||
public readonly double anchor; |
|||
|
|||
public readonly ViewportOffset offset; |
|||
|
|||
public readonly Key center; |
|||
|
|||
public readonly double? cacheExtent; |
|||
|
|||
public static AxisDirection getDefaultCrossAxisDirection(BuildContext context, AxisDirection axisDirection) { |
|||
switch (axisDirection) { |
|||
case AxisDirection.up: |
|||
return AxisUtils.textDirectionToAxisDirection(Directionality.of(context)); |
|||
case AxisDirection.right: |
|||
return AxisDirection.down; |
|||
case AxisDirection.down: |
|||
return AxisUtils.textDirectionToAxisDirection(Directionality.of(context)); |
|||
case AxisDirection.left: |
|||
return AxisDirection.down; |
|||
} |
|||
|
|||
|
|||
throw new Exception("unknown axisDirection"); |
|||
} |
|||
|
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new RenderViewport( |
|||
axisDirection: this.axisDirection, |
|||
crossAxisDirection: this.crossAxisDirection ?? |
|||
Viewport.getDefaultCrossAxisDirection(context, this.axisDirection), |
|||
anchor: this.anchor, |
|||
offset: this.offset, |
|||
cacheExtent: this.cacheExtent |
|||
); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObjectRaw) { |
|||
var renderObject = (RenderViewport) renderObjectRaw; |
|||
renderObject.axisDirection = this.axisDirection; |
|||
renderObject.crossAxisDirection = this.crossAxisDirection ?? |
|||
Viewport.getDefaultCrossAxisDirection(context, this.axisDirection); |
|||
renderObject.anchor = this.anchor; |
|||
renderObject.offset = this.offset; |
|||
renderObject.cacheExtent = this.cacheExtent ?? RenderAbstractViewportUtils.defaultCacheExtent; |
|||
} |
|||
|
|||
public override Element createElement() { |
|||
return new _ViewportElement(this); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<AxisDirection>("axisDirection", this.axisDirection)); |
|||
properties.add(new EnumProperty<AxisDirection?>("crossAxisDirection", this.crossAxisDirection, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
properties.add(new DoubleProperty("anchor", this.anchor)); |
|||
properties.add(new DiagnosticsProperty<ViewportOffset>("offset", this.offset)); |
|||
if (this.center != null) { |
|||
properties.add(new DiagnosticsProperty<Key>("center", this.center)); |
|||
} else if (this.children.isNotEmpty() && this.children.First().key != null) { |
|||
properties.add(new DiagnosticsProperty<Key>("center", this.children.First().key, tooltip: "implicit")); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
class _ViewportElement : MultiChildRenderObjectElement { |
|||
internal _ViewportElement(Viewport widget) : base(widget) { |
|||
} |
|||
|
|||
public new Viewport widget { |
|||
get { return (Viewport) base.widget; } |
|||
} |
|||
|
|||
public new RenderViewport renderObject { |
|||
get { return (RenderViewport) base.renderObject; } |
|||
} |
|||
|
|||
public override void mount(Element parent, object newSlot) { |
|||
base.mount(parent, newSlot); |
|||
this._updateCenter(); |
|||
} |
|||
|
|||
public override void update(Widget newWidget) { |
|||
base.update(newWidget); |
|||
this._updateCenter(); |
|||
} |
|||
|
|||
void _updateCenter() { |
|||
if (this.widget.center != null) { |
|||
this.renderObject.center = (RenderSliver) this.children.Single( |
|||
element => element.widget.key == this.widget.center).renderObject; |
|||
} else if (this.children.Any()) { |
|||
this.renderObject.center = (RenderSliver) this.children.First().renderObject; |
|||
} else { |
|||
this.renderObject.center = null; |
|||
} |
|||
} |
|||
|
|||
public override void debugVisitOnstageChildren(ElementVisitor visitor) { |
|||
this.children.Where(e => { |
|||
RenderSliver renderSliver = (RenderSliver) e.renderObject; |
|||
return renderSliver.geometry.visible; |
|||
}).ToList().ForEach(e => visitor(e)); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class ShrinkWrappingViewport : MultiChildRenderObjectWidget { |
|||
public ShrinkWrappingViewport( |
|||
Key key = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
AxisDirection? crossAxisDirection = null, |
|||
ViewportOffset offset = null, |
|||
List<Widget> slivers = null |
|||
) : base(key: key, children: slivers) { |
|||
D.assert(offset != null); |
|||
|
|||
this.axisDirection = axisDirection; |
|||
this.crossAxisDirection = crossAxisDirection; |
|||
this.offset = offset; |
|||
} |
|||
|
|||
public readonly AxisDirection axisDirection; |
|||
|
|||
public readonly AxisDirection? crossAxisDirection; |
|||
|
|||
public readonly ViewportOffset offset; |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new RenderShrinkWrappingViewport( |
|||
axisDirection: this.axisDirection, |
|||
crossAxisDirection: this.crossAxisDirection |
|||
?? Viewport.getDefaultCrossAxisDirection(context, this.axisDirection), |
|||
offset: this.offset |
|||
); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObjectRaw) { |
|||
var renderObject = (RenderShrinkWrappingViewport) renderObjectRaw; |
|||
renderObject.axisDirection = this.axisDirection; |
|||
renderObject.crossAxisDirection = this.crossAxisDirection |
|||
?? Viewport.getDefaultCrossAxisDirection(context, this.axisDirection); |
|||
renderObject.offset = this.offset; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<AxisDirection>("axisDirection", this.axisDirection)); |
|||
properties.add(new EnumProperty<AxisDirection?>("crossAxisDirection", this.crossAxisDirection, |
|||
defaultValue: Diagnostics.kNullDefaultValue)); |
|||
properties.add(new DiagnosticsProperty<ViewportOffset>("offset", this.offset)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: cbc0da359825401197d0c5772ebdaac1 |
|||
timeCreated: 1537172721 |
撰写
预览
正在加载...
取消
保存
Reference in new issue