| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter_test/flutter_test.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| void main() { |
| testWidgets('SliverList reverse children (with keys)', (WidgetTester tester) async { |
| final List<int> items = List<int>.generate(20, (int i) => i); |
| const double itemHeight = 300.0; |
| const double viewportHeight = 500.0; |
| |
| const double scrollPosition = 18 * itemHeight; |
| final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items, |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| await tester.pumpAndSettle(); |
| |
| expect(controller.offset, scrollPosition); |
| expect(find.text('Tile 0'), findsNothing); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 18'), findsOneWidget); |
| expect(find.text('Tile 19'), findsOneWidget); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items.reversed.toList(), |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| final int frames = await tester.pumpAndSettle(); |
| expect(frames, 1); // ensures that there is no (animated) bouncing of the scrollable |
| |
| expect(controller.offset, scrollPosition); |
| expect(find.text('Tile 19'), findsNothing); |
| expect(find.text('Tile 18'), findsNothing); |
| expect(find.text('Tile 1'), findsOneWidget); |
| expect(find.text('Tile 0'), findsOneWidget); |
| |
| controller.jumpTo(0.0); |
| await tester.pumpAndSettle(); |
| |
| expect(controller.offset, 0.0); |
| expect(find.text('Tile 19'), findsOneWidget); |
| expect(find.text('Tile 18'), findsOneWidget); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 0'), findsNothing); |
| }); |
| |
| testWidgets('SliverList replace children (with keys)', (WidgetTester tester) async { |
| final List<int> items = List<int>.generate(20, (int i) => i); |
| const double itemHeight = 300.0; |
| const double viewportHeight = 500.0; |
| |
| const double scrollPosition = 18 * itemHeight; |
| final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items, |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| await tester.pumpAndSettle(); |
| |
| expect(controller.offset, scrollPosition); |
| expect(find.text('Tile 0'), findsNothing); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 18'), findsOneWidget); |
| expect(find.text('Tile 19'), findsOneWidget); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items.map<int>((int i) => i + 100).toList(), |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| final int frames = await tester.pumpAndSettle(); |
| expect(frames, 1); // ensures that there is no (animated) bouncing of the scrollable |
| |
| expect(controller.offset, scrollPosition); |
| expect(find.text('Tile 0'), findsNothing); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 18'), findsNothing); |
| expect(find.text('Tile 19'), findsNothing); |
| |
| expect(find.text('Tile 100'), findsNothing); |
| expect(find.text('Tile 101'), findsNothing); |
| expect(find.text('Tile 118'), findsOneWidget); |
| expect(find.text('Tile 119'), findsOneWidget); |
| |
| controller.jumpTo(0.0); |
| await tester.pumpAndSettle(); |
| |
| expect(controller.offset, 0.0); |
| expect(find.text('Tile 100'), findsOneWidget); |
| expect(find.text('Tile 101'), findsOneWidget); |
| expect(find.text('Tile 118'), findsNothing); |
| expect(find.text('Tile 119'), findsNothing); |
| }); |
| |
| testWidgets('SliverList replace with shorter children list (with keys)', (WidgetTester tester) async { |
| final List<int> items = List<int>.generate(20, (int i) => i); |
| const double itemHeight = 300.0; |
| const double viewportHeight = 500.0; |
| |
| final double scrollPosition = items.length * itemHeight - viewportHeight; |
| final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items, |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| await tester.pumpAndSettle(); |
| |
| expect(controller.offset, scrollPosition); |
| expect(find.text('Tile 0'), findsNothing); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 17'), findsNothing); |
| expect(find.text('Tile 18'), findsOneWidget); |
| expect(find.text('Tile 19'), findsOneWidget); |
| |
| await tester.pumpWidget(_buildSliverList( |
| items: items.sublist(0, items.length - 1), |
| controller: controller, |
| itemHeight: itemHeight, |
| viewportHeight: viewportHeight, |
| )); |
| final int frames = await tester.pumpAndSettle(); |
| expect(frames, greaterThan(1)); // ensure animation to bring tile17 into view |
| |
| expect(controller.offset, scrollPosition - itemHeight); |
| expect(find.text('Tile 0'), findsNothing); |
| expect(find.text('Tile 1'), findsNothing); |
| expect(find.text('Tile 17'), findsOneWidget); |
| expect(find.text('Tile 18'), findsOneWidget); |
| expect(find.text('Tile 19'), findsNothing); |
| }); |
| } |
| |
| Widget _buildSliverList({ |
| List<int> items = const <int>[], |
| ScrollController controller, |
| double itemHeight = 500.0, |
| double viewportHeight = 300.0, |
| }) { |
| return Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Container( |
| height: viewportHeight, |
| child: CustomScrollView( |
| controller: controller, |
| slivers: <Widget>[ |
| SliverList( |
| delegate: SliverChildBuilderDelegate( |
| (BuildContext context, int i) { |
| return Container( |
| key: ValueKey<int>(items[i]), |
| height: itemHeight, |
| child: Text('Tile ${items[i]}'), |
| ); |
| }, |
| childCount: items.length, |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| } |