Unverified Commit e03980ec authored by Ming Lyu (CareF)'s avatar Ming Lyu (CareF) Committed by GitHub

separate scroll until visible implementation for lower level accessibility (#62462)

parent 32144161
......@@ -817,26 +817,32 @@ abstract class WidgetController {
/// Shorthand for `Scrollable.ensureVisible(element(finder))`
Future<void> ensureVisible(Finder finder) => Scrollable.ensureVisible(element(finder));
/// Repeatedly scrolls the `scrollable` by `delta` in the
/// Repeatedly scrolls a [Scrollable] by `delta` in the
/// [Scrollable.axisDirection] until `finder` is visible.
///
/// Between each scroll, wait for `duration` time for settling.
///
/// If `scrollable` is `null`, this will find a [Scrollable].
///
/// Throws a [StateError] if `finder` is not found for maximum `maxScrolls`
/// times.
///
/// This is different from [ensureVisible] in that this allows looking for
/// `finder` that is not built yet, but the caller must specify the scrollable
/// that will build child specified by `finder`.
/// that will build child specified by `finder` when there are multiple
///[Scrollable]s.
///
/// See also [dragUntilVisible].
Future<void> scrollUntilVisible(
Finder finder,
Finder scrollable,
double delta, {
Finder scrollable,
int maxScrolls = 50,
Duration duration = const Duration(milliseconds: 50),
}
) {
assert(maxScrolls > 0);
scrollable ??= find.byType(Scrollable);
return TestAsyncUtils.guard<void>(() async {
Offset moveStep;
switch(widget<Scrollable>(scrollable).axisDirection) {
......@@ -853,10 +859,33 @@ abstract class WidgetController {
moveStep = Offset(-delta, 0);
break;
}
while(maxScrolls > 0 && finder.evaluate().isEmpty) {
await drag(scrollable, moveStep);
await dragUntilVisible(
finder,
scrollable,
moveStep,
maxIteration: maxScrolls,
duration: duration);
});
}
/// Repeatedly drags the `view` by `moveStep` until `finder` is visible.
///
/// Between each operation, wait for `duration` time for settling.
///
/// Throws a [StateError] if `finder` is not found for maximum `maxIteration`
/// times.
Future<void> dragUntilVisible(
Finder finder,
Finder view,
Offset moveStep, {
int maxIteration = 50,
Duration duration = const Duration(milliseconds: 50),
}) {
return TestAsyncUtils.guard<void>(() async {
while(maxIteration > 0 && finder.evaluate().isEmpty) {
await drag(view, moveStep);
await pump(duration);
maxScrolls -= 1;
maxIteration-= 1;
}
await Scrollable.ensureVisible(element(finder));
});
......
......@@ -551,7 +551,7 @@ void main() {
);
testWidgets(
'ensureVisibl: scrolls to make widget visible',
'ensureVisible: scrolls to make widget visible',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
......@@ -596,7 +596,6 @@ void main() {
await tester.scrollUntilVisible(
find.text('Item 45', skipOffstage: false),
find.byType(Scrollable),
100,
);
await tester.pumpAndSettle();
......@@ -628,7 +627,6 @@ void main() {
await tester.scrollUntilVisible(
find.text('Item 45', skipOffstage: false),
find.byType(Scrollable),
100,
);
await tester.pumpAndSettle();
......@@ -656,7 +654,6 @@ void main() {
try {
await tester.scrollUntilVisible(
find.text('Item 55', skipOffstage: false),
find.byType(Scrollable),
100,
);
} on StateError catch (e) {
......@@ -664,5 +661,48 @@ void main() {
}
},
);
testWidgets('Drag Until Visible', (WidgetTester tester) async {
// when there are two implicit [Scrollable], `scrollUntilVisible` is hard
// to use.
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Column(
children: <Widget>[
Container(height: 200, child: ListView.builder(
key: const Key('listView-a'),
itemCount: 50,
shrinkWrap: true,
itemBuilder: (BuildContext context, int i) => ListTile(title: Text('Item a-$i')),
)),
const Divider(thickness: 5),
Expanded(child: ListView.builder(
key: const Key('listView-b'),
itemCount: 50,
shrinkWrap: true,
itemBuilder: (BuildContext context, int i) => ListTile(title: Text('Item b-$i')),
)),
],
),
),
),
);
await tester.pumpAndSettle();
expect(find.byType(Scrollable), findsNWidgets(2));
// Make sure widget isn't built yet.
expect(find.text('Item b-45', skipOffstage: false), findsNothing);
await tester.dragUntilVisible(
find.text('Item b-45', skipOffstage: false),
find.byKey(const ValueKey<String>('listView-b')),
const Offset(0, -100),
);
await tester.pumpAndSettle();
// Now the widget is on screen.
expect(find.text('Item b-45', skipOffstage: true), findsOneWidget);
});
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment