blob: c110a9db7813433fed52602b3c3e6979e9397b49 [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.
// @dart = 2.8
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
class ExpandingBox extends StatefulWidget {
const ExpandingBox({this.collapsedSize, this.expandedSize});
final double collapsedSize;
final double expandedSize;
@override
State<ExpandingBox> createState() => _ExpandingBoxState();
}
class _ExpandingBoxState extends State<ExpandingBox> with AutomaticKeepAliveClientMixin<ExpandingBox>{
double _height;
@override
void initState() {
super.initState();
_height = widget.collapsedSize;
}
void toggleSize() {
setState(() {
_height = _height == widget.collapsedSize ? widget.expandedSize : widget.collapsedSize;
});
}
@override
Widget build(BuildContext context) {
super.build(context);
return Container(
height: _height,
color: Colors.green,
child: Align(
alignment: Alignment.bottomCenter,
child: FlatButton(
child: const Text('Collapse'),
onPressed: toggleSize,
),
),
);
}
@override
bool get wantKeepAlive => true;
}
void main() {
testWidgets('shrink listview', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: ListView.builder(
itemBuilder: (BuildContext context, int index) => index == 0
? const ExpandingBox(collapsedSize: 400, expandedSize: 1200)
: Container(height: 300, color: Colors.red),
itemCount: 2,
),
));
final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
expect(position.activity, isInstanceOf<IdleScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 0.0);
await tester.tap(find.byType(FlatButton));
await tester.pump();
final TestGesture drag1 = await tester.startGesture(const Offset(10.0, 500.0));
await tester.pump();
await drag1.moveTo(const Offset(10.0, 0.0));
await tester.pump();
await drag1.up();
await tester.pump();
expect(position.pixels, moreOrLessEquals(500.0));
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 900.0);
final TestGesture drag2 = await tester.startGesture(const Offset(10.0, 500.0));
await tester.pump();
await drag2.moveTo(const Offset(10.0, 100.0));
await tester.pump();
await drag2.up();
await tester.pump();
expect(position.maxScrollExtent, 900.0);
expect(position.pixels, moreOrLessEquals(900.0));
await tester.pump();
await tester.tap(find.byType(FlatButton));
await tester.pump();
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 100.0);
});
testWidgets('shrink listview while dragging', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: ListView.builder(
itemBuilder: (BuildContext context, int index) => index == 0
? const ExpandingBox(collapsedSize: 400, expandedSize: 1200)
: Container(height: 300, color: Colors.red),
itemCount: 2,
),
));
final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
expect(position.activity, isInstanceOf<IdleScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 0.0);
await tester.tap(find.byType(FlatButton));
await tester.pump(); // start button animation
await tester.pump(const Duration(seconds: 1)); // finish button animation
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 1800.0);
expect(position.pixels, 0.0);
final TestGesture drag1 = await tester.startGesture(const Offset(10.0, 500.0));
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
await drag1.moveTo(const Offset(10.0, 0.0));
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
await drag1.up();
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
expect(position.pixels, moreOrLessEquals(500.0));
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 900.0);
final TestGesture drag2 = await tester.startGesture(const Offset(10.0, 500.0));
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
await drag2.moveTo(const Offset(10.0, 100.0));
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
expect(position.maxScrollExtent, 900.0);
expect(position.pixels, lessThanOrEqualTo(900.0));
expect(position.activity, isInstanceOf<DragScrollActivity>());
final _ExpandingBoxState expandingBoxState = tester.state<_ExpandingBoxState>(find.byType(ExpandingBox));
expandingBoxState.toggleSize();
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
expect(position.activity, isInstanceOf<DragScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 100.0);
await drag2.moveTo(const Offset(10.0, 150.0));
await drag2.up();
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 50.0);
expect(await tester.pumpAndSettle(), 1); // Nothing to animate
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 50.0);
});
testWidgets('shrink listview while ballistic', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: GestureDetector(
onTap: () { assert(false); },
child: ListView.builder(
physics: const RangeMaintainingScrollPhysics(parent: BouncingScrollPhysics()),
itemBuilder: (BuildContext context, int index) => index == 0
? const ExpandingBox(collapsedSize: 400, expandedSize: 1200)
: Container(height: 300, color: Colors.red),
itemCount: 2,
),
),
));
final _ExpandingBoxState expandingBoxState = tester.state<_ExpandingBoxState>(find.byType(ExpandingBox));
expandingBoxState.toggleSize();
final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
expect(position.activity, isInstanceOf<IdleScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 0.0);
await tester.pump();
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 1800.0);
expect(position.pixels, 0.0);
final TestGesture drag1 = await tester.startGesture(const Offset(10.0, 10.0));
await tester.pump();
expect(position.activity, isInstanceOf<HoldScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 1800.0);
expect(position.pixels, 0.0);
await drag1.moveTo(const Offset(10.0, 50.0)); // to get past the slop and trigger the drag
await drag1.moveTo(const Offset(10.0, 550.0));
expect(position.pixels, -500.0);
await tester.pump();
expect(position.activity, isInstanceOf<DragScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 1800.0);
expect(position.pixels, -500.0);
await drag1.up();
await tester.pump();
expect(position.activity, isInstanceOf<BallisticScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 1800.0);
expect(position.pixels, -500.0);
expandingBoxState.toggleSize();
await tester.pump(); // apply physics without moving clock forward
expect(position.activity, isInstanceOf<BallisticScrollActivity>());
// TODO(ianh): Determine why the maxScrollOffset is 200.0 here instead of 100.0 or double.infinity.
// expect(position.minScrollExtent, 0.0);
// expect(position.maxScrollExtent, 100.0);
expect(position.pixels, -500.0);
await tester.pumpAndSettle(); // ignoring the exact effects of the animation
expect(position.activity, isInstanceOf<IdleScrollActivity>());
expect(position.minScrollExtent, 0.0);
expect(position.maxScrollExtent, 100.0);
expect(position.pixels, 0.0);
});
}