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

407 行
14 KiB

using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.physics;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler2;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public enum ScrollPositionAlignmentPolicy {
explicitPolicy,
keepVisibleAtEnd,
keepVisibleAtStart,
}
public abstract class ScrollPosition : ViewportOffset, ScrollMetrics {
protected ScrollPosition(
ScrollPhysics physics = null,
ScrollContext context = null,
bool keepScrollOffset = true,
ScrollPosition oldPosition = null,
string debugLabel = null,
object coordinator = 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;
_coordinator = coordinator;
if (oldPosition != null) {
absorb(oldPosition);
}
if (keepScrollOffset) {
restoreScrollOffset();
}
}
public readonly ScrollPhysics physics;
public readonly ScrollContext context;
public readonly bool keepScrollOffset;
public readonly string debugLabel;
internal readonly object _coordinator;
public float minScrollExtent {
get { return _minScrollExtent.Value; }
}
float? _minScrollExtent;
public float maxScrollExtent {
get { return _maxScrollExtent.Value; }
}
float? _maxScrollExtent;
public bool hasMinScrollExtent {
get { return _minScrollExtent != null; }
}
public bool hasMaxScrollExtent {
get { return _maxScrollExtent != null; }
}
public override float pixels {
get {
D.assert(_pixels != null);
return _pixels ?? 0.0f;
}
}
public bool havePixels {
get { return _pixels != null; }
}
internal float? _pixels;
public float viewportDimension {
get { return _viewportDimension.Value; }
}
float? _viewportDimension;
public bool haveDimensions {
get { return _haveDimensions; }
}
bool _haveDimensions = false;
public abstract AxisDirection axisDirection { get; }
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.GetType() != GetType()) {
activity.resetActivity();
}
context.setIgnorePointer(activity.shouldIgnorePointer);
isScrollingNotifier.value = activity.isScrolling;
}
public virtual float setPixels(float newPixels) {
D.assert(_pixels != null);
D.assert(SchedulerBinding.instance.schedulerPhase <= SchedulerPhase.transientCallbacks);
if (newPixels != pixels) {
float overscroll = applyBoundaryConditions(newPixels);
D.assert(() => {
float delta = newPixels - 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."
, GetType(), pixels, newPixels, delta, overscroll));
}
return true;
});
float oldPixels = pixels;
_pixels = newPixels - overscroll;
if (pixels != oldPixels) {
notifyListeners();
didUpdateScrollPositionBy(pixels - oldPixels);
}
if (overscroll != 0.0) {
didOverscrollBy(overscroll);
return overscroll;
}
}
return 0.0f;
}
public void correctPixels(float value) {
_pixels = value;
}
public override void correctBy(float correction) {
D.assert(
_pixels != null,
() => "An initial pixels value must exist by caling correctPixels on the ScrollPosition"
);
_pixels += correction;
_didChangeViewportDimensionOrReceiveCorrection = true;
}
protected void forcePixels(float value) {
D.assert(_pixels != null);
_pixels = value;
notifyListeners();
}
protected virtual void saveScrollOffset() {
var pageStorage = PageStorage.of(context.storageContext);
if (pageStorage != null) {
pageStorage.writeState(context.storageContext, pixels);
}
}
protected virtual void restoreScrollOffset() {
if (_pixels == null) {
var pageStorage = PageStorage.of(context.storageContext);
if (pageStorage != null) {
object valueRaw = pageStorage.readState(context.storageContext);
if (valueRaw != null) {
correctPixels((float) valueRaw);
}
}
}
}
protected float applyBoundaryConditions(float value) {
float result = physics.applyBoundaryConditions(this, value);
D.assert(() => {
float delta = value - pixels;
if (result.abs() > delta.abs()) {
throw new UIWidgetsError(
$"{physics.GetType()}.applyBoundaryConditions returned invalid overscroll value.\n" +
$"The method was called to consider a change from {pixels} to {value}, which is a " +
$"delta of {delta:F1} units. However, it returned an overscroll of " +
$"${result: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 {minScrollExtent} .. {maxScrollExtent}, and the " +
$"viewport dimension is {viewportDimension}.");
}
return true;
});
return result;
}
bool _didChangeViewportDimensionOrReceiveCorrection = true;
public override bool applyViewportDimension(float viewportDimension) {
if (_viewportDimension != viewportDimension) {
_viewportDimension = viewportDimension;
_didChangeViewportDimensionOrReceiveCorrection = true;
}
return true;
}
public override bool applyContentDimensions(float minScrollExtent, float maxScrollExtent) {
if (!PhysicsUtils.nearEqual(_minScrollExtent, minScrollExtent, Tolerance.defaultTolerance.distance) ||
!PhysicsUtils.nearEqual(_maxScrollExtent, maxScrollExtent, Tolerance.defaultTolerance.distance) ||
_didChangeViewportDimensionOrReceiveCorrection) {
D.assert(minScrollExtent <= maxScrollExtent);
_minScrollExtent = minScrollExtent;
_maxScrollExtent = maxScrollExtent;
_haveDimensions = true;
applyNewDimensions();
_didChangeViewportDimensionOrReceiveCorrection = false;
}
return true;
}
protected virtual void applyNewDimensions() {
D.assert(_pixels != null);
activity.applyNewDimensions();
}
public Future ensureVisible(
RenderObject renderObject,
float alignment = 0.0f,
TimeSpan? duration = null,
Curve curve = null,
ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicitPolicy
) {
D.assert(renderObject.attached);
RenderAbstractViewport viewport = RenderViewportUtils.of(renderObject);
D.assert(viewport != null);
float target = 0f;
switch (alignmentPolicy) {
case ScrollPositionAlignmentPolicy.explicitPolicy:
target = viewport.getOffsetToReveal(renderObject, alignment).offset.clamp(minScrollExtent, maxScrollExtent);
break;
case ScrollPositionAlignmentPolicy.keepVisibleAtEnd:
target = viewport.getOffsetToReveal(renderObject, 1.0f).offset.clamp(minScrollExtent, maxScrollExtent) ;
if (target < pixels) {
target = pixels;
}
break;
case ScrollPositionAlignmentPolicy.keepVisibleAtStart:
target = viewport.getOffsetToReveal(renderObject, 0.0f).offset.clamp(minScrollExtent, maxScrollExtent) ;
if (target > pixels) {
target = pixels;
}
break;
}
if (target == pixels) {
return Future.value();
}
duration = duration ?? TimeSpan.Zero;
if (duration == TimeSpan.Zero) {
jumpTo(target);
return Future.value();
}
curve = curve ?? Curves.ease;
return animateTo(target, duration: duration.Value, curve: curve);
}
public readonly ValueNotifier<bool> isScrollingNotifier = new ValueNotifier<bool>(false);
public override Future moveTo(float to, TimeSpan? duration, Curve curve = null, bool clamp = true) {
if (clamp) {
to = to.clamp(minScrollExtent, maxScrollExtent);
}
return base.moveTo(to, duration: duration, curve: curve, clamp: clamp);
}
public override bool allowImplicitScrolling {
get { return physics.allowImplicitScrolling; }
}
public abstract ScrollHoldController hold(VoidCallback holdCancelCallback);
public abstract Drag drag(DragStartDetails details, VoidCallback dragCancelCallback);
protected ScrollActivity activity {
get { return _activity; }
}
ScrollActivity _activity;
public virtual void beginActivity(ScrollActivity newActivity) {
if (newActivity == null) {
return;
}
bool wasScrolling, oldIgnorePointer;
if (_activity != null) {
oldIgnorePointer = _activity.shouldIgnorePointer;
wasScrolling = _activity.isScrolling;
if (wasScrolling && !newActivity.isScrolling) {
didEndScroll();
}
_activity.dispose();
}
else {
oldIgnorePointer = false;
wasScrolling = false;
}
_activity = newActivity;
if (oldIgnorePointer != activity.shouldIgnorePointer) {
context.setIgnorePointer(activity.shouldIgnorePointer);
}
isScrollingNotifier.value = activity.isScrolling;
if (!wasScrolling && _activity.isScrolling) {
didStartScroll();
}
}
public void didStartScroll() {
activity.dispatchScrollStartNotification(
ScrollMetricsUtils.copyWith(this), context.notificationContext);
}
public void didUpdateScrollPositionBy(float delta) {
activity.dispatchScrollUpdateNotification(
ScrollMetricsUtils.copyWith(this), context.notificationContext, delta);
}
public void didEndScroll() {
activity.dispatchScrollEndNotification(
ScrollMetricsUtils.copyWith(this), context.notificationContext);
if (keepScrollOffset) {
saveScrollOffset();
}
}
public void didOverscrollBy(float value) {
D.assert(activity.isScrolling);
activity.dispatchOverscrollNotification(
ScrollMetricsUtils.copyWith(this), context.notificationContext, value);
}
public void didUpdateScrollDirection(ScrollDirection direction) {
new UserScrollNotification(metrics:
ScrollMetricsUtils.copyWith(this), context: context.notificationContext, direction: direction
).dispatch(context.notificationContext);
}
public bool recommendDeferredLoading(BuildContext context) {
D.assert(context != null);
D.assert(activity != null);
return physics.recommendDeferredLoading(activity.velocity, ScrollMetricsUtils.copyWith(this), context);
}
public override void dispose() {
D.assert(_pixels != null);
if (activity != null) {
activity.dispose();
_activity = null;
}
base.dispose();
}
protected override void debugFillDescription(List<string> description) {
if (debugLabel != null) {
description.Add(debugLabel);
}
base.debugFillDescription(description);
description.Add($"range: {_minScrollExtent:F1}..{_maxScrollExtent:F1}");
description.Add($"viewport: {_viewportDimension:F1}");
}
}
}