float _calculateScrollIncrement(ScrollableState state, ScrollIncrementType type = ScrollIncrementType.line) { D.assert(state.position != null); D.assert(state.position.havePixels); 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); }
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 static Future ensureVisible( BuildContext context, float alignment = 0.0f, TimeSpan?duration = null, Curve curve = null, ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicitPolicy ) { duration = duration ?? TimeSpan.Zero; curve = curve ?? Curves.ease; List <Future> futures = new List <Future>(); ScrollableState scrollable = of(context); while (scrollable != null) { futures.Add(scrollable.position.ensureVisible( context.findRenderObject(), alignment: alignment, duration: duration, curve: curve, alignmentPolicy: alignmentPolicy )); context = scrollable.context; scrollable = of(context); } if (futures.isEmpty() || duration == TimeSpan.Zero) { return(Future.value()); } if (futures.Count == 1) { return(futures.Single()); } return(Future.wait <object>(futures)); }
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.havePixels, () => "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 ); }
public static IPromise ensureVisible(BuildContext context, float alignment = 0.0f, TimeSpan?duration = null, Curve curve = null ) { duration = duration ?? TimeSpan.Zero; curve = curve ?? Curves.ease; List <IPromise> futures = new List <IPromise>(); ScrollableState scrollable = of(context); while (scrollable != null) { futures.Add(scrollable.position.ensureVisible( context.findRenderObject(), alignment: alignment, duration: duration, curve: curve )); context = scrollable.context; scrollable = of(context); } if (futures.isEmpty() || duration == TimeSpan.Zero) { return(Promise.Resolved()); } if (futures.Count == 1) { return(futures.Single()); } return(Promise.All(futures)); }
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); case AxisDirection.down: return(increment); case AxisDirection.right: case AxisDirection.left: return(0.0f); } break; case AxisDirection.up: switch (state.axisDirection) { case AxisDirection.up: return(increment); case AxisDirection.down: return(-increment); case AxisDirection.right: case AxisDirection.left: return(0.0f); } break; case AxisDirection.left: switch (state.axisDirection) { case AxisDirection.right: return(-increment); case AxisDirection.left: return(increment); case AxisDirection.up: case AxisDirection.down: return(0.0f); } break; case AxisDirection.right: switch (state.axisDirection) { case AxisDirection.right: return(increment); case AxisDirection.left: return(-increment); case AxisDirection.up: case AxisDirection.down: return(0.0f); } break; } return(0.0f); }
public override bool inDirection(FocusNode currentNode, TraversalDirection direction) { FocusScopeNode nearestScope = currentNode.nearestScope; FocusNode focusedChild = nearestScope.focusedChild; if (focusedChild == null) { FocusNode firstFocus = findFirstFocusInDirection(currentNode, direction) ?? currentNode; switch (direction) { case TraversalDirection.up: case TraversalDirection.left: FocusTravesalUtils._focusAndEnsureVisible( firstFocus, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart ); break; case TraversalDirection.right: case TraversalDirection.down: FocusTravesalUtils._focusAndEnsureVisible( firstFocus, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd ); break; } return(true); } if (_popPolicyDataIfNeeded(direction, nearestScope, focusedChild)) { return(true); } FocusNode found = null; ScrollableState focusedScrollable = Scrollable.of(focusedChild.context); switch (direction) { case TraversalDirection.down: case TraversalDirection.up: IEnumerable <FocusNode> eligibleNodes = _sortAndFilterVertically( direction, focusedChild.rect, nearestScope.traversalDescendants ); if (focusedScrollable != null && !focusedScrollable.position.atEdge()) { IEnumerable <FocusNode> filteredEligibleNodes = LinqUtils <FocusNode> .WhereList(eligibleNodes, ((FocusNode node) => Scrollable.of(node.context) == focusedScrollable)); if (filteredEligibleNodes.Count() != 0) { eligibleNodes = filteredEligibleNodes; } } if (eligibleNodes.Count() == 0) { break; } List <FocusNode> sorted = eligibleNodes.ToList(); if (direction == TraversalDirection.up) { //sorted = sorted.reversed.toList(); sorted.Reverse(); sorted = sorted.ToList(); } Rect band = Rect.fromLTRB(focusedChild.rect.left, float.NegativeInfinity, focusedChild.rect.right, float.PositiveInfinity); IEnumerable <FocusNode> inBand = LinqUtils <FocusNode> .WhereList(sorted, ((FocusNode node) => !node.rect.intersect(band).isEmpty)); if (inBand.Count() != 0) { found = inBand.First(); break; } FocusTravesalUtils.mergeSort <FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => { return((a.rect.center.dx - focusedChild.rect.center.dx).abs().CompareTo((b.rect.center.dx - focusedChild.rect.center.dx).abs())); }); found = sorted.First(); break; case TraversalDirection.right: case TraversalDirection.left: eligibleNodes = _sortAndFilterHorizontally(direction, focusedChild.rect, nearestScope); if (focusedScrollable != null && !focusedScrollable.position.atEdge()) { IEnumerable <FocusNode> filteredEligibleNodes = LinqUtils <FocusNode> .WhereList(eligibleNodes, ((FocusNode node) => Scrollable.of(node.context) == focusedScrollable)); if (filteredEligibleNodes.Count() != 0) { eligibleNodes = filteredEligibleNodes; } } if (eligibleNodes.Count() == 0) { break; } sorted = eligibleNodes.ToList(); if (direction == TraversalDirection.left) { sorted.Reverse(); sorted = sorted.ToList(); //sorted = sorted.reversed.toList(); } band = Rect.fromLTRB(float.NegativeInfinity, focusedChild.rect.top, float.PositiveInfinity, focusedChild.rect.bottom); inBand = LinqUtils <FocusNode> .WhereList(sorted, ((FocusNode node) => !node.rect.intersect(band).isEmpty)); if (inBand.Count() != 0) { found = inBand.First(); break; } FocusTravesalUtils.mergeSort <FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => { return((a.rect.center.dy - focusedChild.rect.center.dy).abs().CompareTo((b.rect.center.dy - focusedChild.rect.center.dy).abs())); }); found = sorted.First(); break; } if (found != null) { _pushPolicyData(direction, nearestScope, focusedChild); switch (direction) { case TraversalDirection.up: case TraversalDirection.left: FocusTravesalUtils._focusAndEnsureVisible( found, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart ); break; case TraversalDirection.down: case TraversalDirection.right: FocusTravesalUtils._focusAndEnsureVisible( found, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd ); break; } return(true); } return(false); }