blob: bc83ab014fbf4b807ff0bcf667ee486984cc2bec [file] [log] [blame]
// Copyright 2014 The Flutter 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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
List<TreeSliverNode<String>> _setUpNodes() {
return <TreeSliverNode<String>>[
TreeSliverNode<String>('First'),
TreeSliverNode<String>(
'Second',
children: <TreeSliverNode<String>>[
TreeSliverNode<String>(
'alpha',
children: <TreeSliverNode<String>>[
TreeSliverNode<String>('uno'),
TreeSliverNode<String>('dos'),
TreeSliverNode<String>('tres'),
],
),
TreeSliverNode<String>('beta'),
TreeSliverNode<String>('kappa'),
],
),
TreeSliverNode<String>(
'Third',
expanded: true,
children: <TreeSliverNode<String>>[
TreeSliverNode<String>('gamma'),
TreeSliverNode<String>('delta'),
TreeSliverNode<String>('epsilon'),
],
),
TreeSliverNode<String>('Fourth'),
];
}
List<TreeSliverNode<String>> treeNodes = _setUpNodes();
void main() {
testWidgets('asserts proper axis directions', (WidgetTester tester) async {
final List<Object?> exceptions = <Object?>[];
final FlutterExceptionHandler? oldHandler = FlutterError.onError;
FlutterError.onError = (FlutterErrorDetails details) {
exceptions.add(details.exception);
};
addTearDown(() {
FlutterError.onError = oldHandler;
});
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(
reverse: true,
slivers: <Widget>[TreeSliver<String>(tree: treeNodes)],
),
),
);
FlutterError.onError = oldHandler;
expect(exceptions.isNotEmpty, isTrue);
expect(
exceptions[0].toString(),
contains('TreeSliver is only supported in Viewports with an AxisDirection.down.'),
);
exceptions.clear();
await tester.pumpWidget(Container());
FlutterError.onError = (FlutterErrorDetails details) {
exceptions.add(details.exception);
};
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
slivers: <Widget>[TreeSliver<String>(tree: treeNodes)],
),
),
);
FlutterError.onError = oldHandler;
expect(exceptions.isNotEmpty, isTrue);
expect(
exceptions[0].toString(),
contains('TreeSliver is only supported in Viewports with an AxisDirection.down.'),
);
exceptions.clear();
await tester.pumpWidget(Container());
FlutterError.onError = (FlutterErrorDetails details) {
exceptions.add(details.exception);
};
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(
scrollDirection: Axis.horizontal,
slivers: <Widget>[TreeSliver<String>(tree: treeNodes)],
),
),
);
FlutterError.onError = oldHandler;
expect(exceptions.isNotEmpty, isTrue);
expect(
exceptions[0].toString(),
contains('TreeSliver is only supported in Viewports with an AxisDirection.down.'),
);
});
testWidgets('Basic layout', (WidgetTester tester) async {
treeNodes = _setUpNodes();
// Default layout, custom indentation values, row extents.
TreeSliver<String> treeSliver = TreeSliver<String>(tree: treeNodes);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('First'), findsOneWidget);
expect(tester.getRect(find.text('First')), const Rect.fromLTRB(46.0, 8.0, 286.0, 32.0));
expect(find.text('Second'), findsOneWidget);
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
expect(find.text('Third'), findsOneWidget);
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(find.text('gamma'), findsOneWidget);
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
expect(find.text('delta'), findsOneWidget);
expect(tester.getRect(find.text('delta')), const Rect.fromLTRB(46.0, 168.0, 286.0, 192.0));
expect(find.text('epsilon'), findsOneWidget);
expect(tester.getRect(find.text('epsilon')), const Rect.fromLTRB(46.0, 208.0, 382.0, 232.0));
expect(find.text('Fourth'), findsOneWidget);
expect(tester.getRect(find.text('Fourth')), const Rect.fromLTRB(46.0, 248.0, 334.0, 272.0));
treeSliver = TreeSliver<String>(tree: treeNodes, indentation: TreeSliverIndentationType.none);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(46.0, 128.0))
..paragraph(offset: const Offset(46.0, 168.0))
..paragraph(offset: const Offset(46.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('First'), findsOneWidget);
expect(tester.getRect(find.text('First')), const Rect.fromLTRB(46.0, 8.0, 286.0, 32.0));
expect(find.text('Second'), findsOneWidget);
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
expect(find.text('Third'), findsOneWidget);
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(find.text('gamma'), findsOneWidget);
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
expect(find.text('delta'), findsOneWidget);
expect(tester.getRect(find.text('delta')), const Rect.fromLTRB(46.0, 168.0, 286.0, 192.0));
expect(find.text('epsilon'), findsOneWidget);
expect(tester.getRect(find.text('epsilon')), const Rect.fromLTRB(46.0, 208.0, 382.0, 232.0));
expect(find.text('Fourth'), findsOneWidget);
expect(tester.getRect(find.text('Fourth')), const Rect.fromLTRB(46.0, 248.0, 334.0, 272.0));
treeSliver = TreeSliver<String>(
tree: treeNodes,
indentation: TreeSliverIndentationType.custom(50.0),
);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(96.0, 128.0))
..paragraph(offset: const Offset(96.0, 168.0))
..paragraph(offset: const Offset(96.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('First'), findsOneWidget);
expect(tester.getRect(find.text('First')), const Rect.fromLTRB(46.0, 8.0, 286.0, 32.0));
expect(find.text('Second'), findsOneWidget);
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
expect(find.text('Third'), findsOneWidget);
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(find.text('gamma'), findsOneWidget);
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
expect(find.text('delta'), findsOneWidget);
expect(tester.getRect(find.text('delta')), const Rect.fromLTRB(46.0, 168.0, 286.0, 192.0));
expect(find.text('epsilon'), findsOneWidget);
expect(tester.getRect(find.text('epsilon')), const Rect.fromLTRB(46.0, 208.0, 382.0, 232.0));
expect(find.text('Fourth'), findsOneWidget);
expect(tester.getRect(find.text('Fourth')), const Rect.fromLTRB(46.0, 248.0, 334.0, 272.0));
treeSliver = TreeSliver<String>(tree: treeNodes, treeRowExtentBuilder: (_, _) => 100);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 26.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 126.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 226.0))
..paragraph(offset: const Offset(56.0, 326.0))
..paragraph(offset: const Offset(56.0, 426.0))
..paragraph(offset: const Offset(56.0, 526.0)),
);
expect(find.text('First'), findsOneWidget);
expect(tester.getRect(find.text('First')), const Rect.fromLTRB(46.0, 26.0, 286.0, 74.0));
expect(find.text('Second'), findsOneWidget);
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 126.0, 334.0, 174.0));
expect(find.text('Third'), findsOneWidget);
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 226.0, 286.0, 274.0));
expect(find.text('gamma'), findsOneWidget);
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 326.0, 286.0, 374.0));
expect(find.text('delta'), findsOneWidget);
expect(tester.getRect(find.text('delta')), const Rect.fromLTRB(46.0, 426.0, 286.0, 474.0));
expect(find.text('epsilon'), findsOneWidget);
expect(tester.getRect(find.text('epsilon')), const Rect.fromLTRB(46.0, 526.0, 382.0, 574.0));
expect(find.text('Fourth'), findsNothing);
});
testWidgets('Animating node segment', (WidgetTester tester) async {
treeNodes = _setUpNodes();
TreeSliver<String> treeSliver = TreeSliver<String>(tree: treeNodes);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('alpha'), findsNothing);
await tester.tap(find.byType(Icon).first);
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph(offset: const Offset(56.0, 8.0)) // beta animating in
..paragraph(offset: const Offset(56.0, 48.0)) // kappa animating in
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
// New nodes have been inserted into the tree, alpha
// is not visible yet.
expect(find.text('alpha'), findsNothing);
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')), const Rect.fromLTRB(46.0, 8.0, 238.0, 32.0));
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')), const Rect.fromLTRB(46.0, 48.0, 286.0, 72.0));
// Progress the animation.
await tester.pump(const Duration(milliseconds: 50));
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // alpha icon
..paragraph(offset: const Offset(56.0, 8.0)) // alpha animating in
..paragraph(offset: const Offset(56.0, 48.0)) // beta animating in
..paragraph(offset: const Offset(56.0, 88.0)) // kappa animating in
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(56.0, 248.0))
..paragraph(offset: const Offset(46.0, 288.0)),
);
expect(tester.getRect(find.text('alpha')).top.floor(), 8.0);
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')).top.floor(), 48.0);
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')).top.floor(), 88.0);
// Complete the animation
await tester.pumpAndSettle();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0)) // First
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0)) // Second
..paragraph() // alpha icon
..paragraph(offset: const Offset(56.0, 88.0)) // alpha
..paragraph(offset: const Offset(56.0, 128.0)) // beta
..paragraph(offset: const Offset(56.0, 168.0)) // kappa
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 208.0)) // Third
..paragraph(offset: const Offset(56.0, 248.0)) // gamma
..paragraph(offset: const Offset(56.0, 288.0)) // delta
..paragraph(offset: const Offset(56.0, 328.0)) // epsilon
..paragraph(offset: const Offset(46.0, 368.0)), // Fourth
);
expect(find.text('alpha'), findsOneWidget);
expect(tester.getRect(find.text('alpha')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')), const Rect.fromLTRB(46.0, 128.0, 238.0, 152.0));
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')), const Rect.fromLTRB(46.0, 168.0, 286.0, 192.0));
// Customize the animation
treeSliver = TreeSliver<String>(
tree: treeNodes,
toggleAnimationStyle: AnimationStyle(
duration: const Duration(milliseconds: 500),
curve: Curves.bounceIn,
),
);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0)) // First
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0)) // Second
..paragraph() // alpha icon
..paragraph(offset: const Offset(56.0, 88.0)) // alpha
..paragraph(offset: const Offset(56.0, 128.0)) // beta
..paragraph(offset: const Offset(56.0, 168.0)) // kappa
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 208.0)) // Third
..paragraph(offset: const Offset(56.0, 248.0)) // gamma
..paragraph(offset: const Offset(56.0, 288.0)) // delta
..paragraph(offset: const Offset(56.0, 328.0)) // epsilon
..paragraph(offset: const Offset(46.0, 368.0)), // Fourth
);
// Still visible from earlier.
expect(find.text('alpha'), findsOneWidget);
expect(tester.getRect(find.text('alpha')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
// Collapse the node now
await tester.tap(find.byType(Icon).first);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('alpha'), findsOneWidget);
expect(tester.getRect(find.text('alpha')).top.floor(), -22);
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')).top.floor(), 18);
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')).top.floor(), 58);
// Progress the animation.
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('alpha'), findsOneWidget);
expect(tester.getRect(find.text('alpha')).top.floor(), -25);
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')).top.floor(), 15);
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')).top.floor(), 55.0);
// Complete the animation
await tester.pumpAndSettle();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('alpha'), findsNothing);
// Disable the animation
treeSliver = TreeSliver<String>(
tree: treeNodes,
toggleAnimationStyle: AnimationStyle.noAnimation,
);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
// Not in the tree.
expect(find.text('alpha'), findsNothing);
// Collapse the node now
await tester.tap(find.byType(Icon).first);
await tester.pump();
// No animating, straight to positions.
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0)) // First
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0)) // Second
..paragraph() // alpha icon
..paragraph(offset: const Offset(56.0, 88.0)) // alpha
..paragraph(offset: const Offset(56.0, 128.0)) // beta
..paragraph(offset: const Offset(56.0, 168.0)) // kappa
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 208.0)) // Third
..paragraph(offset: const Offset(56.0, 248.0)) // gamma
..paragraph(offset: const Offset(56.0, 288.0)) // delta
..paragraph(offset: const Offset(56.0, 328.0)) // epsilon
..paragraph(offset: const Offset(46.0, 368.0)), // Fourth
);
expect(find.text('alpha'), findsOneWidget);
expect(tester.getRect(find.text('alpha')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(find.text('beta'), findsOneWidget);
expect(tester.getRect(find.text('beta')), const Rect.fromLTRB(46.0, 128.0, 238.0, 152.0));
expect(find.text('kappa'), findsOneWidget);
expect(tester.getRect(find.text('kappa')), const Rect.fromLTRB(46.0, 168.0, 286.0, 192.0));
});
testWidgets('Multiple animating node segments', (WidgetTester tester) async {
treeNodes = _setUpNodes();
final TreeSliver<String> treeSliver = TreeSliver<String>(tree: treeNodes);
await tester.pumpWidget(MaterialApp(home: CustomScrollView(slivers: <Widget>[treeSliver])));
await tester.pump();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(find.text('Second'), findsOneWidget);
expect(find.text('alpha'), findsNothing); // Second is collapsed
expect(find.text('Third'), findsOneWidget);
expect(find.text('gamma'), findsOneWidget); // Third is expanded
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
// Trigger two animations to run together.
// Collapse Third
await tester.tap(find.byType(Icon).last);
// Expand Second
await tester.tap(find.byType(Icon).first);
await tester.pump(const Duration(milliseconds: 15));
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph(offset: const Offset(56.0, 8.0)) // beta entering
..paragraph(offset: const Offset(56.0, 48.0)) // kappa entering
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
// Third is collapsing
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
// Second is expanding
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
// beta has been added and is animating into view.
expect(tester.getRect(find.text('beta')).top.floor(), 8.0);
await tester.pump(const Duration(milliseconds: 15));
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // alpha icon animating
..paragraph(offset: const Offset(56.0, -20.0)) // alpha animating
..paragraph(offset: const Offset(56.0, 20.0)) // beta
..paragraph(offset: const Offset(56.0, 60.0)) // kappa
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 100.0)) // Third
// Children of Third are animating, but the expand and
// collapse counter each other, so their position is unchanged.
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
// Third is still collapsing. Third is sliding down
// as Seconds's children slide in, gamma is still exiting.
expect(tester.getRect(find.text('Third')).top.floor(), 100.0);
// gamma appears to not have moved, this is because it is
// intersecting both animations, the positive offset of
// Second animation == the negative offset of Third
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
// Second is still expanding
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
// alpha is still animating into view.
expect(tester.getRect(find.text('alpha')).top.floor(), -20.0);
// Progress the animation further
await tester.pump(const Duration(milliseconds: 15));
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // alpha icon animating
..paragraph(offset: const Offset(56.0, -8.0)) // alpha animating
..paragraph(offset: const Offset(56.0, 32.0)) // beta
..paragraph(offset: const Offset(56.0, 72.0)) // kappa
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 112.0)) // Third
// Children of Third are animating, but the expand and
// collapse counter each other, so their position is unchanged.
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph(offset: const Offset(56.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
// Third is still collapsing. Third is sliding down
// as Seconds's children slide in, gamma is still exiting.
expect(tester.getRect(find.text('Third')).top.floor(), 112.0);
// gamma appears to not have moved, this is because it is
// intersecting both animations, the positive offset of
// Second animation == the negative offset of Third
expect(tester.getRect(find.text('gamma')), const Rect.fromLTRB(46.0, 128.0, 286.0, 152.0));
// Second is still expanding
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
// alpha is still animating into view.
expect(tester.getRect(find.text('alpha')).top.floor(), -8.0);
// Complete the animations
await tester.pumpAndSettle();
expect(
find.byType(TreeSliver<String>),
paints
..paragraph(offset: const Offset(46.0, 8.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 48.0))
..paragraph() // Icon
..paragraph(offset: const Offset(56.0, 88.0))
..paragraph(offset: const Offset(56.0, 128.0))
..paragraph(offset: const Offset(56.0, 168.0))
..paragraph() // Icon
..paragraph(offset: const Offset(46.0, 208.0))
..paragraph(offset: const Offset(46.0, 248.0)),
);
expect(tester.getRect(find.text('Third')), const Rect.fromLTRB(46.0, 208.0, 286.0, 232.0));
// gamma has left the building
expect(find.text('gamma'), findsNothing);
expect(tester.getRect(find.text('Second')), const Rect.fromLTRB(46.0, 48.0, 334.0, 72.0));
// alpha is in place.
expect(tester.getRect(find.text('alpha')), const Rect.fromLTRB(46.0, 88.0, 286.0, 112.0));
});
testWidgets('only paints visible rows', (WidgetTester tester) async {
treeNodes = _setUpNodes();
final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
treeNodes = _setUpNodes();
final TreeSliver<String> treeSliver = TreeSliver<String>(
treeRowExtentBuilder: (_, _) => 200,
tree: treeNodes,
);
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(controller: scrollController, slivers: <Widget>[treeSliver]),
),
);
await tester.pump();
expect(scrollController.position.pixels, 0.0);
expect(scrollController.position.maxScrollExtent, 800.0);
bool rowNeedsPaint(String row) {
return find.text(row).evaluate().first.renderObject!.debugNeedsPaint;
}
expect(rowNeedsPaint('First'), isFalse);
expect(rowNeedsPaint('Second'), isFalse);
expect(rowNeedsPaint('Third'), isFalse);
expect(find.text('gamma'), findsNothing); // Not visible
// Change the scroll offset
scrollController.jumpTo(200);
await tester.pump();
expect(find.text('First'), findsNothing);
expect(rowNeedsPaint('Second'), isFalse);
expect(rowNeedsPaint('Third'), isFalse);
expect(rowNeedsPaint('gamma'), isFalse); // Now visible
});
}