scrollUntilVisible method

Future<void> scrollUntilVisible (SerializableFinder scrollable, SerializableFinder item, { double alignment: 0.0, double dxScroll: 0.0, double dyScroll: 0.0, Duration timeout: const Duration(seconds: 10) })

Repeatedly scroll the widget located by scrollable by dxScroll and dyScroll until item is visible, and then use scrollIntoView to ensure the item's final position matches alignment.

The scrollable must locate the scrolling widget that contains item. Typically find.byType('ListView') or find.byType('CustomScrollView').

At least one of dxScroll and dyScroll must be non-zero.

If item is below the currently visible items, then specify a negative value for dyScroll that's a small enough increment to expose item without potentially scrolling it up and completely out of view. Similarly if item is above, then specify a positive value for dyScroll.

If item is to the right of the currently visible items, then specify a negative value for dxScroll that's a small enough increment to expose item without potentially scrolling it up and completely out of view. Similarly if item is to the left, then specify a positive value for dyScroll.

The timeout value should be long enough to accommodate as many scrolls as needed to bring an item into view. The default is 10 seconds.

Implementation

Future<void> scrollUntilVisible(SerializableFinder scrollable, SerializableFinder item, {
  double alignment = 0.0,
  double dxScroll = 0.0,
  double dyScroll = 0.0,
  Duration timeout = const Duration(seconds: 10),
}) async {
  assert(scrollable != null);
  assert(item != null);
  assert(alignment != null);
  assert(dxScroll != null);
  assert(dyScroll != null);
  assert(dxScroll != 0.0 || dyScroll != 0.0);
  assert(timeout != null);

  // Kick off an (unawaited) waitFor that will complete when the item we're
  // looking for finally scrolls onscreen. We add an initial pause to give it
  // the chance to complete if the item is already onscreen; if not, scroll
  // repeatedly until we either find the item or time out.
  bool isVisible = false;
  waitFor(item, timeout: timeout).then<void>((_) { isVisible = true; });
  await Future<void>.delayed(const Duration(milliseconds: 500));
  while (!isVisible) {
    await scroll(scrollable, dxScroll, dyScroll, const Duration(milliseconds: 100));
    await Future<void>.delayed(const Duration(milliseconds: 500));
  }

  return scrollIntoView(item, alignment: alignment);
}