浏览代码

Merge pull request #51 from Unity-Technologies/upgrade_scroll_widgets

Upgrade scroll widgets
/siyaoH-1.17-PlatformMessage
GitHub 4 年前
当前提交
80379726
共有 10 个文件被更改,包括 507 次插入160 次删除
  1. 51
      com.unity.uiwidgets/Runtime/widgets/nested_scroll_view.cs
  2. 6
      com.unity.uiwidgets/Runtime/widgets/overscroll_indicator.cs
  3. 5
      com.unity.uiwidgets/Runtime/widgets/primary_scroll_controller.cs
  4. 7
      com.unity.uiwidgets/Runtime/widgets/scroll_configuration.cs
  5. 9
      com.unity.uiwidgets/Runtime/widgets/scroll_metrics.cs
  6. 29
      com.unity.uiwidgets/Runtime/widgets/scroll_physics.cs
  7. 7
      com.unity.uiwidgets/Runtime/widgets/scroll_position.cs
  8. 91
      com.unity.uiwidgets/Runtime/widgets/scroll_view.cs
  9. 173
      com.unity.uiwidgets/Runtime/widgets/scrollable.cs
  10. 289
      com.unity.uiwidgets/Runtime/widgets/scrollbar.cs

51
com.unity.uiwidgets/Runtime/widgets/nested_scroll_view.cs


public readonly DragStartBehavior dragStartBehavior;
public static SliverOverlapAbsorberHandle sliverOverlapAbsorberHandleFor(BuildContext context) {
_InheritedNestedScrollView target =
(_InheritedNestedScrollView) context.inheritFromWidgetOfExactType(typeof(_InheritedNestedScrollView));
_InheritedNestedScrollView target = context.dependOnInheritedWidgetOfExactType<_InheritedNestedScrollView>();
() => {
return
"NestedScrollView.sliverOverlapAbsorberHandleFor must be called with a context that contains a NestedScrollView.";
});
() => "NestedScrollView.sliverOverlapAbsorberHandleFor must be called with a context that contains a NestedScrollView."
);
List<Widget> slivers = new List<Widget> { };
List<Widget> slivers = new List<Widget>();
slivers.AddRange(headerSliverBuilder(context, bodyIsScrolled));
slivers.Add(new SliverFillRemaining(
child: new PrimaryScrollController(

}
public override State createState() {
return new _NestedScrollViewState();
return new NestedScrollViewState();
class _NestedScrollViewState : State<NestedScrollView> {
internal SliverOverlapAbsorberHandle _absorberHandle = new SliverOverlapAbsorberHandle();
class NestedScrollViewState : State<NestedScrollView> {
internal readonly SliverOverlapAbsorberHandle _absorberHandle = new SliverOverlapAbsorberHandle();
ScrollController innerController => _coordinator._innerController;
ScrollController outerController => _coordinator._outerController;
_NestedScrollCoordinator _coordinator;

class _InheritedNestedScrollView : InheritedWidget {
public _InheritedNestedScrollView(
Key key = null,
_NestedScrollViewState state = null,
NestedScrollViewState state = null,
Widget child = null
) : base(key: key, child: child) {
D.assert(state != null);

public readonly _NestedScrollViewState state;
public readonly NestedScrollViewState state;
public override bool updateShouldNotify(InheritedWidget _old) {
_InheritedNestedScrollView old = _old as _InheritedNestedScrollView;

class _NestedScrollCoordinator : ScrollActivityDelegate, ScrollHoldController {
public _NestedScrollCoordinator(
_NestedScrollViewState _state,
NestedScrollViewState _state,
ScrollController _parent,
VoidCallback _onHasScrolledBodyChanged) {
float initialScrollOffset = _parent?.initialScrollOffset ?? 0.0f;

this._onHasScrolledBodyChanged = _onHasScrolledBodyChanged;
}
public readonly _NestedScrollViewState _state;
public readonly NestedScrollViewState _state;
ScrollController _parent;
public readonly VoidCallback _onHasScrolledBodyChanged;

float velocity) {
return position.createBallisticScrollActivity(
position.physics.createBallisticSimulation(
velocity == 0 ? (ScrollMetrics) position : _getMetrics(position, velocity),
velocity == 0f ? (ScrollMetrics) position : _getMetrics(position, velocity),
velocity
),
mode: _NestedBallisticScrollActivityMode.inner

public SliverOverlapAbsorber(
Key key = null,
SliverOverlapAbsorberHandle handle = null,
Widget child = null
) : base(key: key, child: child) {
Widget child = null,
Widget sliver = null
) : base(key: key, child: sliver ?? child) {
D.assert(child == null || sliver == null);
this.handle = handle;
}

public class RenderSliverOverlapAbsorber : RenderObjectWithChildMixinRenderSliver<RenderSliver> {
public RenderSliverOverlapAbsorber(
SliverOverlapAbsorberHandle handle,
RenderSliver child = null
RenderSliver child = null,
RenderSliver sliver = null
D.assert(child == null || sliver == null);
this.child = child;
this.child = sliver ?? child;
}
public SliverOverlapAbsorberHandle handle {

scrollExtent: childLayoutGeometry.scrollExtent - childLayoutGeometry.maxScrollObstructionExtent,
paintExtent: childLayoutGeometry.paintExtent,
paintOrigin: childLayoutGeometry.paintOrigin,
layoutExtent: childLayoutGeometry.paintExtent - childLayoutGeometry.maxScrollObstructionExtent,
layoutExtent: Mathf.Max(0, childLayoutGeometry.paintExtent - childLayoutGeometry.maxScrollObstructionExtent),
maxPaintExtent: childLayoutGeometry.maxPaintExtent,
maxScrollObstructionExtent: childLayoutGeometry.maxScrollObstructionExtent,
hitTestExtent: childLayoutGeometry.hitTestExtent,

public SliverOverlapInjector(
Key key = null,
SliverOverlapAbsorberHandle handle = null,
Widget child = null
) : base(key: key, child: child) {
Widget child = null,
Widget sliver = null
) : base(key: key, child: sliver ?? child) {
D.assert(child == null || sliver == null);
this.handle = handle;
}

6
com.unity.uiwidgets/Runtime/widgets/overscroll_indicator.cs


}
properties.add(new MessageProperty("show", showDescription));
properties.add(new DiagnosticsProperty<Color>("color", color, showName: false));
properties.add(new ColorProperty("color", color, showName: false));
}
}

}
if (notification is OverscrollNotification) {
_GlowController controller;
_GlowController controller = null;
OverscrollNotification _notification = notification as OverscrollNotification;
if (_notification.overscroll < 0.0f) {
controller = _leadingController;

}
else {
throw new Exception("overscroll is 0.0f!");
D.assert(false, () =>"over scroll cannot be 0.0f.");
}
bool isLeading = controller == _leadingController;

5
com.unity.uiwidgets/Runtime/widgets/primary_scroll_controller.cs


public readonly ScrollController controller;
public static ScrollController of(BuildContext context) {
PrimaryScrollController result =
(PrimaryScrollController) context.inheritFromWidgetOfExactType(typeof(PrimaryScrollController));
return result == null ? null : result.controller;
PrimaryScrollController result = context.dependOnInheritedWidgetOfExactType<PrimaryScrollController>();
return result?.controller;
}
public override bool updateShouldNotify(InheritedWidget oldWidget) {

7
com.unity.uiwidgets/Runtime/widgets/scroll_configuration.cs


}
public virtual ScrollPhysics getScrollPhysics(BuildContext context) {
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS
#else
return new ClampingScrollPhysics();
#endif
}
public virtual bool shouldNotify(ScrollBehavior oldDelegate) {

public readonly ScrollBehavior behavior;
public static ScrollBehavior of(BuildContext context) {
ScrollConfiguration configuration =
(ScrollConfiguration) context.inheritFromWidgetOfExactType(typeof(ScrollConfiguration));
ScrollConfiguration configuration = context.dependOnInheritedWidgetOfExactType<ScrollConfiguration>();
if (configuration != null) {
return configuration.behavior;
}

9
com.unity.uiwidgets/Runtime/widgets/scroll_metrics.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.widgets {

}
public static float extentInside(this ScrollMetrics it) {
return Mathf.Min(it.pixels, it.maxScrollExtent) -
Mathf.Max(it.pixels, it.minScrollExtent) +
Mathf.Min(it.viewportDimension, it.maxScrollExtent - it.minScrollExtent);
D.assert(it.minScrollExtent <= it.maxScrollExtent);
return it.viewportDimension
- (it.minScrollExtent - it.pixels).clamp(0, it.viewportDimension)
- (it.pixels - it.maxScrollExtent).clamp(0, it.viewportDimension);
}
public static float extentAfter(this ScrollMetrics it) {

29
com.unity.uiwidgets/Runtime/widgets/scroll_physics.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.physics;

}
return parent.shouldAcceptUserOffset(position);
}
public bool recommendDeferredLoading(float velocity, ScrollMetrics metrics, BuildContext context) {
D.assert(metrics != null);
D.assert(context != null);
if (parent == null) {
float maxPhysicalPixels = WidgetsBinding.instance.window.physicalSize.longestSide;
return velocity.abs() > maxPhysicalPixels;
}
return parent.recommendDeferredLoading(velocity, metrics, context);
}
public virtual float applyBoundaryConditions(ScrollMetrics position, float value) {

public override float applyBoundaryConditions(ScrollMetrics position, float value) {
D.assert(() => {
if (value == position.pixels) {
throw new UIWidgetsError(
$"{GetType()}.applyBoundaryConditions() was called redundantly.\n" +
$"The proposed new position, {value}, is exactly equal to the current position of the " +
$"given {position.GetType()}, {position.pixels}.\n" +
"The applyBoundaryConditions method should only be called when the value is " +
"going to actually change the pixels, otherwise it is redundant.\n" +
"The physics object in question was:\n" + $" {this}\n" +
"The position object in question was:\n" + $" {position}\n");
throw new UIWidgetsError(new List<DiagnosticsNode>() {
new ErrorSummary($"{GetType()}.applyBoundaryConditions() was called redundantly."),
new ErrorDescription($"The proposed new position, {value}, is exactly equal to the current position of the " +
$"given {position.GetType()}, {position.pixels}.\n" +
"The applyBoundaryConditions method should only be called when the value is " +
"going to actually change the pixels, otherwise it is redundant."),
new DiagnosticsProperty<ScrollPhysics>("The physics object in question was", this, style: DiagnosticsTreeStyle.errorProperty),
new DiagnosticsProperty<ScrollMetrics>("The position object in question was", position, style: DiagnosticsTreeStyle.errorProperty)
});
}
return true;

7
com.unity.uiwidgets/Runtime/widgets/scroll_position.cs


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;

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() {

91
com.unity.uiwidgets/Runtime/widgets/scroll_view.cs


using UnityEngine;
namespace Unity.UIWidgets.widgets {
public enum ScrollViewKeyboardDismissBehavior {
manual,
onDrag
}
public abstract class ScrollView : StatelessWidget {
protected ScrollView(
Key key = null,

Key center = null,
float anchor = 0.0f,
float? cacheExtent = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) : base(key: key) {
D.assert(!(controller != null && primary == true),
() => "Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. " +

this.anchor = anchor;
this.cacheExtent = cacheExtent;
this.dragStartBehavior = dragStartBehavior;
this.keyboardDismissBehavior = keyboardDismissBehavior;
}
public readonly Axis scrollDirection;

public readonly float anchor;
public readonly float? cacheExtent;
public readonly DragStartBehavior dragStartBehavior;
public readonly ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
protected AxisDirection getDirection(BuildContext context) {
return LayoutUtils.getAxisDirectionFromAxisReverseAndDirectionality(

viewportBuilder: (viewportContext, offset) =>
buildViewport(viewportContext, offset, axisDirection, slivers)
);
return primary && scrollController != null
Widget scrollableResult = primary && scrollController != null
if (keyboardDismissBehavior == ScrollViewKeyboardDismissBehavior.onDrag) {
return new NotificationListener<ScrollUpdateNotification>(
child: scrollableResult,
onNotification: (ScrollUpdateNotification notification) => {
FocusScopeNode focusScope = FocusScope.of(context);
if (notification.dragDetails != null && focusScope.hasFocus) {
focusScope.unfocus();
}
return false;
}
);
}
else {
return scrollableResult;
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

bool shrinkWrap = false,
EdgeInsets padding = null,
float? cacheExtent = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) : base(
key: key,
scrollDirection: scrollDirection,

physics: physics,
shrinkWrap: shrinkWrap,
cacheExtent: cacheExtent,
dragStartBehavior: dragStartBehavior
dragStartBehavior: dragStartBehavior,
keyboardDismissBehavior: keyboardDismissBehavior
) {
this.padding = padding;
}

bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) : base(
key: key,
scrollDirection: scrollDirection,

shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent,
dragStartBehavior: dragStartBehavior
dragStartBehavior: dragStartBehavior,
keyboardDismissBehavior: keyboardDismissBehavior
) {
this.itemExtent = itemExtent;
childrenDelegate = new SliverChildListDelegate(

bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) : base(key: key,
scrollDirection: scrollDirection,
reverse: reverse,

shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent,
dragStartBehavior: dragStartBehavior
dragStartBehavior: dragStartBehavior,
keyboardDismissBehavior: keyboardDismissBehavior
D.assert(itemCount == null || itemCount >= 0);
this.itemExtent = itemExtent;
childrenDelegate = new SliverChildBuilderDelegate(
itemBuilder,

bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) {
return new ListView(
key: key,

itemCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
dragStartBehavior: dragStartBehavior
dragStartBehavior: dragStartBehavior,
keyboardDismissBehavior: keyboardDismissBehavior
);
}

bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) : base(
key: key,
scrollDirection: scrollDirection,

shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent,
dragStartBehavior: dragStartBehavior
dragStartBehavior: dragStartBehavior,
keyboardDismissBehavior: keyboardDismissBehavior
) {
D.assert(itemBuilder != null);
D.assert(separatorBuilder != null);

(context, index) => {
int itemIndex = index / 2;
return index % 2 == 0
? itemBuilder(context, itemIndex)
: separatorBuilder(context, itemIndex);
Widget widget = null;
if (index % 2 == 0) {
widget = itemBuilder(context, itemIndex);
}
else {
widget = separatorBuilder(context, itemIndex);
D.assert(() => {
if (widget == null) {
throw new UIWidgetsError("separatorBuilder cannot return null.");
}
return true;
});
}
return widget;
childCount: Mathf.Max(0, itemCount * 2 - 1),
childCount: _computeActualChildCount(itemCount),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);

int itemCount = 0,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null
float? cacheExtent = null,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual
) {
return new ListView(
key,

itemCount,
addAutomaticKeepAlives,
addRepaintBoundaries,
cacheExtent
cacheExtent,
keyboardDismissBehavior: keyboardDismissBehavior
);
}

base.debugFillProperties(properties);
properties.add(new FloatProperty("itemExtent", itemExtent,
defaultValue: foundation_.kNullDefaultValue));
}
static int _computeActualChildCount(int itemCount) {
return Mathf.Max(0, itemCount * 2 - 1);
}
}

173
com.unity.uiwidgets/Runtime/widgets/scrollable.cs


ScrollController controller = null,
ScrollPhysics physics = null,
ViewportBuilder viewportBuilder = null,
ScrollIncrementCalculator incrementCalculator = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start
) : base(key: key) {
D.assert(viewportBuilder != null);

this.physics = physics;
this.viewportBuilder = viewportBuilder;
this.incrementCalculator = incrementCalculator;
this.dragStartBehavior = dragStartBehavior;
}

public readonly ScrollPhysics physics;
public readonly ViewportBuilder viewportBuilder;
public readonly ScrollIncrementCalculator incrementCalculator;
public readonly DragStartBehavior dragStartBehavior;

}
public static ScrollableState of(BuildContext context) {
_ScrollableScope widget = (_ScrollableScope) context.inheritFromWidgetOfExactType(typeof(_ScrollableScope));
_ScrollableScope widget = context.dependOnInheritedWidgetOfExactType<_ScrollableScope>();
}
static bool recommendDeferredLoadingForContext(BuildContext context) {
_ScrollableScope widget = context.getElementForInheritedWidgetOfExactType<_ScrollableScope>()?.widget as _ScrollableScope;
if (widget == null) {
return false;
}
return widget.position.recommendDeferredLoading(context);
}
public static Future ensureVisible(

float _targetScrollOffsetForPointerScroll(PointerScrollEvent e) {
float delta = widget.axis == Axis.horizontal ? e.delta.dx : e.delta.dy;
if (AxisUtils.axisDirectionIsReversed(widget.axisDirection)) {
delta += -1;
}
return Mathf.Min(Mathf.Max(position.pixels + delta, position.minScrollExtent),
position.maxScrollExtent);
}

void _handlePointerScroll(PointerEvent e) {
D.assert(e is PointerScrollEvent);
if (_physics != null && !_physics.shouldAcceptUserOffset(position)) {
return;
}
float targetScrollOffset = _targetScrollOffsetForPointerScroll(e as PointerScrollEvent);
if (targetScrollOffset != position.pixels) {
position.jumpTo(targetScrollOffset);

public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<ScrollPosition>("position", position));
}
}
public delegate float ScrollIncrementCalculator(ScrollIncrementDetails details);
public enum ScrollIncrementType {
line,
page
}
public class ScrollIncrementDetails {
public ScrollIncrementDetails(
ScrollIncrementType type,
ScrollMetrics metrics
) {
D.assert(metrics != null);
this.type = type;
this.metrics = metrics;
}
public readonly ScrollIncrementType type;
public readonly ScrollMetrics metrics;
}
public class ScrollIntent : Intent {
public ScrollIntent(
AxisDirection direction,
ScrollIncrementType type = ScrollIncrementType.line
) : base (ScrollAction.key) {
this.direction = direction;
this.type = type;
}
public readonly AxisDirection direction;
public readonly ScrollIncrementType type;
protected bool isEnabled(BuildContext context) {
return Scrollable.of(context) != null;
}
}
public class ScrollAction : UiWidgetAction {
public ScrollAction() : base(key) {
}
public static readonly LocalKey key = new ValueKey<Type>(typeof(ScrollAction));
float _calculateScrollIncrement(ScrollableState state, ScrollIncrementType type = ScrollIncrementType.line) {
D.assert(state.position != null);
D.assert(state.position.pixels != null);
D.assert(state.widget.physics == null || state.widget.physics.shouldAcceptUserOffset(state.position));
if (state.widget.incrementCalculator != null) {
return state.widget.incrementCalculator(
new ScrollIncrementDetails(
type: type,
metrics: state.position
)
);
}
switch (type) {
case ScrollIncrementType.line:
return 50.0f;
case ScrollIncrementType.page:
return 0.8f * state.position.viewportDimension;
}
return 0.0f;
}
float _getIncrement(ScrollableState state, ScrollIntent intent) {
float increment = _calculateScrollIncrement(state, type: intent.type);
switch (intent.direction) {
case AxisDirection.down:
switch (state.axisDirection) {
case AxisDirection.up:
return -increment;
break;
case AxisDirection.down:
return increment;
break;
case AxisDirection.right:
case AxisDirection.left:
return 0.0f;
}
break;
case AxisDirection.up:
switch (state.axisDirection) {
case AxisDirection.up:
return increment;
break;
case AxisDirection.down:
return -increment;
break;
case AxisDirection.right:
case AxisDirection.left:
return 0.0f;
}
break;
case AxisDirection.left:
switch (state.axisDirection) {
case AxisDirection.right:
return -increment;
break;
case AxisDirection.left:
return increment;
break;
case AxisDirection.up:
case AxisDirection.down:
return 0.0f;
}
break;
case AxisDirection.right:
switch (state.axisDirection) {
case AxisDirection.right:
return increment;
break;
case AxisDirection.left:
return -increment;
break;
case AxisDirection.up:
case AxisDirection.down:
return 0.0f;
}
break;
}
return 0.0f;
}
public override void invoke(FocusNode node, Intent intent) {
ScrollableState state = Scrollable.of(node.context);
D.assert(state != null, () => "ScrollAction was invoked on a context that has no scrollable parent");
D.assert(state.position.pixels != null, () => "Scrollable must be laid out before it can be scrolled via a ScrollAction");
if (state.widget.physics != null && !state.widget.physics.shouldAcceptUserOffset(state.position)) {
return;
}
float increment = _getIncrement(state, intent as ScrollIntent);
if (increment == 0.0f) {
return;
}
state.position.moveTo(
state.position.pixels + increment,
duration: TimeSpan.FromMilliseconds(100),
curve: Curves.easeInOut
);
}
}
}

289
com.unity.uiwidgets/Runtime/widgets/scrollbar.cs


using Rect = Unity.UIWidgets.ui.Rect;
namespace Unity.UIWidgets.widgets {
static class ScrollbarPainterUtils {
public const float _kMinThumbExtent = 18.0f;
public const float _kMinInteractiveSize = 48.0f;
}
public class ScrollbarPainter : ChangeNotifier, CustomPainter {
public ScrollbarPainter(
Color color,

EdgeInsets padding = null,
float minLength = _kMinThumbExtent,
float minOverscrollLength = _kMinThumbExtent
float minLength = ScrollbarPainterUtils._kMinThumbExtent,
float? minOverscrollLength = null
this.color = color;
this.textDirection = textDirection;
D.assert(color != null);
D.assert(fadeoutOpacityAnimation != null);
D.assert(minLength >= 0);
D.assert(minOverscrollLength == null || minOverscrollLength.Value <= minLength);
D.assert(minOverscrollLength == null || minOverscrollLength.Value >= 0);
padding = padding ?? EdgeInsets.zero;
D.assert(padding.isNonNegative);
_color = color;
_textDirection = textDirection;
_padding = padding;
this.thickness = thickness;
this.fadeoutOpacityAnimation = fadeoutOpacityAnimation;
this.mainAxisMargin = mainAxisMargin;

this.minOverscrollLength = minOverscrollLength;
this.minOverscrollLength = minOverscrollLength ?? minLength;
const float _kMinThumbExtent = 18.0f;
public Color color {
get { return _color; }
set {
D.assert(value != null);
if (color == value) {
return;
}
_color = value;
notifyListeners();
}
}
Color _color;
public Color color;
public TextDirection? textDirection;
public TextDirection textDirection {
get { return _textDirection; }
set {
if (textDirection == value) {
return;
}
_textDirection = value;
notifyListeners();
}
}
TextDirection _textDirection;
public Animation<float> fadeoutOpacityAnimation;
public float mainAxisMargin;
public float crossAxisMargin;
public readonly Animation<float> fadeoutOpacityAnimation;
public readonly float mainAxisMargin;
public readonly float crossAxisMargin;
public float minLength;
public float minOverscrollLength;
public EdgeInsets padding {
get { return _padding; }
set {
D.assert(value != null);
if (padding == value) {
return;
}
_padding = value;
notifyListeners();
}
}
EdgeInsets _padding;
public readonly float minLength;
public readonly float minOverscrollLength;
Rect _thumbRect;
public void update(ScrollMetrics metrics, AxisDirection axisDirection) {
_lastMetrics = metrics;

void updateThickness(float nextThickness, Radius nextRadius) {
thickness = nextThickness;
radius = nextRadius;
notifyListeners();
}
Paint _paint {
get {
var paint = new Paint();

}
void _paintThumbCrossAxis(Canvas canvas, Size size, float thumbOffset, float thumbExtent, AxisDirection direction) {
float x = 0;
float y = 0;
Size thumbSize = Size.zero;
float _getThumbX(Size size) {
D.assert(textDirection != null);
switch (textDirection) {
case TextDirection.rtl:
return crossAxisMargin;
case TextDirection.ltr:
return size.width - thickness - crossAxisMargin;
switch (direction) {
case AxisDirection.down:
thumbSize = new Size(thickness, thumbExtent);
x = textDirection == TextDirection.rtl
? crossAxisMargin + padding.left
: size.width - thickness - crossAxisMargin - padding.right;
y = thumbOffset;
break;
case AxisDirection.up:
thumbSize = new Size(thickness, thumbExtent);
x = textDirection == TextDirection.rtl
? crossAxisMargin + padding.left
: size.width - thickness - crossAxisMargin - padding.right;
y = thumbOffset;
break;
case AxisDirection.left:
thumbSize = new Size(thumbExtent, thickness);
x = thumbOffset;
y = size.height - thickness - crossAxisMargin - padding.bottom;
break;
case AxisDirection.right:
thumbSize = new Size(thumbExtent, thickness);
x = thumbOffset;
y = size.height - thickness - crossAxisMargin - padding.bottom;
break;
return 0;
}
void _paintVerticalThumb(Canvas canvas, Size size, float thumbOffset, float thumbExtent) {
Offset thumbOrigin = new Offset(_getThumbX(size), thumbOffset);
Size thumbSize = new Size(thickness, thumbExtent);
Rect thumbRect = thumbOrigin & thumbSize;
_thumbRect = new Offset(x, y) & thumbSize;
canvas.drawRect(thumbRect, _paint);
canvas.drawRect(_thumbRect, _paint);
canvas.drawRRect(RRect.fromRectAndRadius(thumbRect, radius), _paint);
canvas.drawRRect(RRect.fromRectAndRadius(_thumbRect, radius), _paint);
float _thumbExtent() {
float fractionVisible = ((_lastMetrics.extentInside() - _mainAxisPadding) / (_totalContentExtent - _mainAxisPadding))
.clamp(0.0f, 1.0f);
void _paintHorizontalThumb(Canvas canvas, Size size, float thumbOffset, float thumbExtent) {
Offset thumbOrigin = new Offset(thumbOffset, size.height - thickness);
Size thumbSize = new Size(thumbExtent, thickness);
Rect thumbRect = thumbOrigin & thumbSize;
if (radius == null) {
canvas.drawRect(thumbRect, _paint);
}
else {
canvas.drawRRect(RRect.fromRectAndRadius(thumbRect, radius), _paint);
}
}
float thumbExtent = Mathf.Max(
Mathf.Min(_trackExtent, minOverscrollLength),
_trackExtent * fractionVisible
);
public delegate void painterDelegate(Canvas canvas, Size size, float thumbOffset, float thumbExtent);
void _paintThumb(
float before,
float inside,
float after,
float viewport,
Canvas canvas,
Size size,
painterDelegate painter
) {
float thumbExtent = Mathf.Min(viewport, minOverscrollLength);
if (before + inside + after > 0.0) {
float fractionVisible = inside / (before + inside + after);
thumbExtent = Mathf.Max(
thumbExtent,
viewport * fractionVisible - 2 * mainAxisMargin
);
if (before != 0.0 && after != 0.0) {
thumbExtent = Mathf.Max(
minLength,
thumbExtent
);
}
else {
thumbExtent = Mathf.Max(
thumbExtent,
minLength * (((inside / viewport) - 0.8f) / 0.2f)
);
}
float fractionPast = before / (before + after);
float thumbOffset = (before + after > 0.0)
? fractionPast * (viewport - thumbExtent - 2 * mainAxisMargin) + mainAxisMargin
: mainAxisMargin;
painter(canvas, size, thumbOffset, thumbExtent);
}
float fractionOverscrolled = 1.0f - _lastMetrics.extentInside() / _lastMetrics.viewportDimension;
float safeMinLength = Mathf.Min(minLength, _trackExtent);
float newMinLength = (_beforeExtent > 0 && _afterExtent > 0)
? safeMinLength
: safeMinLength * (1.0f - fractionOverscrolled.clamp(0.0f, 0.2f) / 0.2f);
return thumbExtent.clamp(newMinLength, _trackExtent);
}
public override void dispose() {

bool _isVertical => _lastAxisDirection == AxisDirection.down || _lastAxisDirection == AxisDirection.up;
bool _isReversed => _lastAxisDirection == AxisDirection.up || _lastAxisDirection == AxisDirection.left;
float _beforeExtent => _isReversed ? _lastMetrics.extentAfter() : _lastMetrics.extentBefore();
float _afterExtent => _isReversed ? _lastMetrics.extentBefore() : _lastMetrics.extentAfter();
float _mainAxisPadding => _isVertical ? padding.vertical : padding.horizontal;
float _trackExtent => _lastMetrics.viewportDimension - 2 * mainAxisMargin - _mainAxisPadding;
float _totalContentExtent {
get {
return _lastMetrics.maxScrollExtent
- _lastMetrics.minScrollExtent
+ _lastMetrics.viewportDimension;
}
}
float getTrackToScroll(float thumbOffsetLocal) {
float scrollableExtent = _lastMetrics.maxScrollExtent - _lastMetrics.minScrollExtent;
float thumbMovableExtent = _trackExtent - _thumbExtent();
return scrollableExtent * thumbOffsetLocal / thumbMovableExtent;
}
float _getScrollToTrack(ScrollMetrics metrics, float thumbExtent) {
float scrollableExtent = metrics.maxScrollExtent - metrics.minScrollExtent;
float fractionPast = (scrollableExtent > 0)
? ((metrics.pixels - metrics.minScrollExtent) / scrollableExtent).clamp(0.0f, 1.0f)
: 0;
return (_isReversed ? 1 - fractionPast : fractionPast) * (_trackExtent - thumbExtent);
}
|| fadeoutOpacityAnimation.value == 0.0) {
|| fadeoutOpacityAnimation.value == 0.0f) {
switch (_lastAxisDirection) {
case AxisDirection.down:
_paintThumb(_lastMetrics.extentBefore(), _lastMetrics.extentInside(),
_lastMetrics.extentAfter(), size.height, canvas, size, _paintVerticalThumb);
break;
case AxisDirection.up:
_paintThumb(_lastMetrics.extentAfter(), _lastMetrics.extentInside(),
_lastMetrics.extentBefore(), size.height, canvas, size, _paintVerticalThumb);
break;
case AxisDirection.right:
_paintThumb(_lastMetrics.extentBefore(), _lastMetrics.extentInside(),
_lastMetrics.extentAfter(), size.width, canvas, size, _paintHorizontalThumb);
break;
case AxisDirection.left:
_paintThumb(_lastMetrics.extentAfter(), _lastMetrics.extentInside(),
_lastMetrics.extentBefore(), size.width, canvas, size, _paintHorizontalThumb);
break;
if (_lastMetrics.viewportDimension <= _mainAxisPadding || _trackExtent <= 0) {
return;
float beforePadding = _isVertical ? padding.top : padding.left;
float thumbExtent = _thumbExtent();
float thumbOffsetLocal = _getScrollToTrack(_lastMetrics, thumbExtent);
float thumbOffset = thumbOffsetLocal + mainAxisMargin + beforePadding;
_paintThumbCrossAxis(canvas, size, thumbOffset, thumbExtent, _lastAxisDirection.Value);
}
bool hitTestInteractive(Offset position) {
if (_thumbRect == null) {
return false;
}
if (fadeoutOpacityAnimation.value == 0.0f) {
return false;
}
Rect interactiveThumbRect = _thumbRect.expandToInclude(
Rect.fromCircle(center: _thumbRect.center, radius: ScrollbarPainterUtils._kMinInteractiveSize / 2)
);
return interactiveThumbRect.contains(position);
return false;
if (_thumbRect == null) {
return null;
}
if (fadeoutOpacityAnimation.value == 0.0f) {
return false;
}
return _thumbRect.contains(position);
}
public bool shouldRepaint(CustomPainter oldRaw) {

|| mainAxisMargin != old.mainAxisMargin
|| crossAxisMargin != old.crossAxisMargin
|| radius != old.radius
|| minLength != old.minLength;
|| minLength != old.minLength
|| padding != old.padding;
}
return false;

正在加载...
取消
保存