mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Create CarouselView
widget - Part 2 (#149775)
This PR is to create `Carousel.weighted` so the size of each carousel item is based on a list of weights. While scrolling, item sizes are changing dynamically based on the scrolling progress. https://github.com/flutter/flutter/assets/36861262/181472b0-6f8b-48e7-b191-ab5f7c88c0c8
This commit is contained in:
parent
6d0bb94456
commit
844eb2fe76
@ -17,7 +17,14 @@ class CarouselExampleApp extends StatelessWidget {
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Carousel Sample'),
|
||||
leading: const Icon(Icons.cast),
|
||||
title: const Text('Flutter TV'),
|
||||
actions: const <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsetsDirectional.only(end: 16.0),
|
||||
child: CircleAvatar(child: Icon(Icons.account_circle)),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: const CarouselExample(),
|
||||
),
|
||||
@ -33,19 +40,140 @@ class CarouselExample extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CarouselExampleState extends State<CarouselExample> {
|
||||
final CarouselController controller = CarouselController(initialItem: 1);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
child: CarouselView(
|
||||
itemExtent: 330,
|
||||
shrinkExtent: 200,
|
||||
children: List<Widget>.generate(20, (int index) {
|
||||
return UncontainedLayoutCard(index: index, label: 'Item $index');
|
||||
}),
|
||||
final double height = MediaQuery.sizeOf(context).height;
|
||||
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: height / 2),
|
||||
child: CarouselView.weighted(
|
||||
controller: controller,
|
||||
itemSnapping: true,
|
||||
flexWeights: const <int>[1, 7, 1],
|
||||
children: ImageInfo.values.map((ImageInfo image) {
|
||||
return HeroLayoutCard(imageInfo: image);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Padding(
|
||||
padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0),
|
||||
child: Text('Multi-browse layout'),
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 50),
|
||||
child: CarouselView.weighted(
|
||||
flexWeights: const <int>[1, 2, 3, 2, 1],
|
||||
consumeMaxWeight: false,
|
||||
children: List<Widget>.generate(20, (int index) {
|
||||
return ColoredBox(
|
||||
color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.8),
|
||||
child: const SizedBox.expand(),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
child: CarouselView.weighted(
|
||||
flexWeights: const <int>[3, 3, 3, 2, 1],
|
||||
consumeMaxWeight: false,
|
||||
children: CardInfo.values.map((CardInfo info) {
|
||||
return ColoredBox(
|
||||
color: info.backgroundColor,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Icon(info.icon, color: info.color, size: 32.0),
|
||||
Text(info.label, style: const TextStyle(fontWeight: FontWeight.bold), overflow: TextOverflow.clip, softWrap: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList()
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Padding(
|
||||
padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0),
|
||||
child: Text('Uncontained layout'),
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
child: CarouselView(
|
||||
itemExtent: 330,
|
||||
shrinkExtent: 200,
|
||||
children: List<Widget>.generate(20, (int index){
|
||||
return UncontainedLayoutCard(index: index, label: 'Show $index');
|
||||
}),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HeroLayoutCard extends StatelessWidget {
|
||||
const HeroLayoutCard({
|
||||
super.key,
|
||||
required this.imageInfo,
|
||||
});
|
||||
|
||||
final ImageInfo imageInfo;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double width = MediaQuery.sizeOf(context).width;
|
||||
return Stack(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
children: <Widget>[
|
||||
ClipRect(
|
||||
child: OverflowBox(
|
||||
maxWidth: width * 7 / 8,
|
||||
minWidth: width * 7 / 8,
|
||||
child: Image(
|
||||
fit: BoxFit.cover,
|
||||
image: NetworkImage(
|
||||
'https://flutter.github.io/assets-for-api-docs/assets/material/${imageInfo.url}'
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
imageInfo.title,
|
||||
overflow: TextOverflow.clip,
|
||||
softWrap: false,
|
||||
style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
imageInfo.subtitle,
|
||||
overflow: TextOverflow.clip,
|
||||
softWrap: false,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -75,3 +203,34 @@ class UncontainedLayoutCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum CardInfo {
|
||||
camera('Cameras', Icons.video_call, Color(0xff2354C7), Color(0xffECEFFD)),
|
||||
lighting('Lighting', Icons.lightbulb, Color(0xff806C2A), Color(0xffFAEEDF)),
|
||||
climate('Climate', Icons.thermostat, Color(0xffA44D2A), Color(0xffFAEDE7)),
|
||||
wifi('Wifi', Icons.wifi, Color(0xff417345), Color(0xffE5F4E0)),
|
||||
media('Media', Icons.library_music, Color(0xff2556C8), Color(0xffECEFFD)),
|
||||
security('Security', Icons.crisis_alert, Color(0xff794C01), Color(0xffFAEEDF)),
|
||||
safety('Safety', Icons.medical_services, Color(0xff2251C5), Color(0xffECEFFD)),
|
||||
more('', Icons.add, Color(0xff201D1C), Color(0xffE3DFD8));
|
||||
|
||||
const CardInfo(this.label, this.icon, this.color, this.backgroundColor);
|
||||
final String label;
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final Color backgroundColor;
|
||||
}
|
||||
|
||||
enum ImageInfo {
|
||||
image0('The Flow', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_1.png'),
|
||||
image1('Through the Pane', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_2.png'),
|
||||
image2('Iridescence', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_3.png'),
|
||||
image3('Sea Change', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_4.png'),
|
||||
image4('Blue Symphony', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_5.png'),
|
||||
image5('When It Rains', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_6.png');
|
||||
|
||||
const ImageInfo(this.title, this.subtitle, this.url);
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final String url;
|
||||
}
|
||||
|
@ -2,18 +2,44 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_api_samples/material/carousel/carousel.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
|
||||
// The app being tested loads images via HTTP which the test
|
||||
// framework defeats by default.
|
||||
setUpAll(() {
|
||||
HttpOverrides.global = null;
|
||||
});
|
||||
|
||||
testWidgets('Carousel Smoke Test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.CarouselExampleApp(),
|
||||
);
|
||||
expect(find.byType(CarouselView), findsOneWidget);
|
||||
|
||||
expect(find.widgetWithText(example.UncontainedLayoutCard, 'Item 0'), findsOneWidget);
|
||||
expect(find.widgetWithText(example.UncontainedLayoutCard, 'Item 1'), findsOneWidget);
|
||||
expect(find.widgetWithText(example.HeroLayoutCard, 'Through the Pane'), findsOneWidget);
|
||||
final Finder firstCarousel = find.byType(CarouselView).first;
|
||||
await tester.drag(firstCarousel, const Offset(150, 0));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.widgetWithText(example.HeroLayoutCard, 'The Flow'), findsOneWidget);
|
||||
|
||||
await tester.drag(firstCarousel, const Offset(0, -200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.widgetWithText(CarouselView, 'Cameras'), findsOneWidget);
|
||||
expect(find.widgetWithText(CarouselView, 'Lighting'), findsOneWidget);
|
||||
expect(find.widgetWithText(CarouselView, 'Climate'), findsOneWidget);
|
||||
expect(find.widgetWithText(CarouselView, 'Wifi'), findsOneWidget);
|
||||
|
||||
await tester.drag(find.widgetWithText(CarouselView, 'Cameras'), const Offset(0, -200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Uncontained layout'), findsOneWidget);
|
||||
expect(find.widgetWithText(CarouselView, 'Show 0'), findsOneWidget);
|
||||
expect(find.widgetWithText(CarouselView, 'Show 1'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,12 +26,12 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
final Finder carouselMaterial = find.descendant(
|
||||
final Finder carouselViewMaterial = find.descendant(
|
||||
of: find.byType(CarouselView),
|
||||
matching: find.byType(Material),
|
||||
).first;
|
||||
|
||||
final Material material = tester.widget<Material>(carouselMaterial);
|
||||
final Material material = tester.widget<Material>(carouselViewMaterial);
|
||||
expect(material.clipBehavior, Clip.antiAlias);
|
||||
expect(material.color, colorScheme.surface);
|
||||
expect(material.elevation, 0.0);
|
||||
@ -80,13 +80,13 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
final Finder carouselMaterial = find.descendant(
|
||||
final Finder carouselViewMaterial = find.descendant(
|
||||
of: find.byType(CarouselView),
|
||||
matching: find.byType(Material),
|
||||
).first;
|
||||
|
||||
expect(tester.getSize(carouselMaterial).width, 200 - 20 - 20); // Padding is 20 on both side.
|
||||
final Material material = tester.widget<Material>(carouselMaterial);
|
||||
expect(tester.getSize(carouselViewMaterial).width, 200 - 20 - 20); // Padding is 20 on both side.
|
||||
final Material material = tester.widget<Material>(carouselViewMaterial);
|
||||
expect(material.color, Colors.amber);
|
||||
expect(material.elevation, 10.0);
|
||||
expect(material.shape, const StadiumBorder());
|
||||
@ -110,7 +110,7 @@ void main() {
|
||||
await gesture.removePointer();
|
||||
|
||||
// On focused.
|
||||
final Element inkWellElement = tester.element(find.descendant(of: carouselMaterial, matching: find.byType(InkWell)));
|
||||
final Element inkWellElement = tester.element(find.descendant(of: carouselViewMaterial, matching: find.byType(InkWell)));
|
||||
expect(inkWellElement.widget, isA<InkWell>());
|
||||
final InkWell inkWell = inkWellElement.widget as InkWell;
|
||||
|
||||
@ -145,12 +145,12 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
final Finder item1 = find.byKey(keys.elementAt(1));
|
||||
final Finder item1 = find.byKey(keys[1]);
|
||||
await tester.tap(find.ancestor(of: item1, matching: find.byType(Stack)));
|
||||
await tester.pump();
|
||||
expect(tapIndex, 1);
|
||||
|
||||
final Finder item2 = find.byKey(keys.elementAt(2));
|
||||
final Finder item2 = find.byKey(keys[2]);
|
||||
await tester.tap(find.ancestor(of: item2, matching: find.byType(Stack)));
|
||||
await tester.pump();
|
||||
expect(tapIndex, 2);
|
||||
@ -194,15 +194,73 @@ void main() {
|
||||
expect(find.text('Item 4'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselController initialItem', (WidgetTester tester) async {
|
||||
final CarouselController controller = CarouselController(initialItem: 5);
|
||||
addTearDown(controller.dispose);
|
||||
testWidgets('CarouselView.weighted layout', (WidgetTester tester) async {
|
||||
Widget buildCarouselView({ required List<int> weights }) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
flexWeights: weights,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildCarouselView(weights: <int>[4, 3, 2, 1]));
|
||||
|
||||
final Size viewportSize = MediaQuery.of(tester.element(find.byType(CarouselView))).size;
|
||||
expect(viewportSize, const Size(800, 600));
|
||||
|
||||
expect(find.text('Item 0'), findsOneWidget);
|
||||
Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item width is 4/10 of the viewport.
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 0.0, 320.0, 600.0));
|
||||
|
||||
expect(find.text('Item 1'), findsOneWidget);
|
||||
Rect rect1 = tester.getRect(getItem(1));
|
||||
// Item width is 3/10 of the viewport.
|
||||
expect(rect1, const Rect.fromLTRB(320.0, 0.0, 560.0, 600.0));
|
||||
|
||||
expect(find.text('Item 2'), findsOneWidget);
|
||||
final Rect rect2 = tester.getRect(getItem(2));
|
||||
// Item width is 2/10 of the viewport.
|
||||
expect(rect2, const Rect.fromLTRB(560.0, 0.0, 720.0, 600.0));
|
||||
|
||||
expect(find.text('Item 3'), findsOneWidget);
|
||||
final Rect rect3 = tester.getRect(getItem(3));
|
||||
// Item width is 1/10 of the viewport.
|
||||
expect(rect3, const Rect.fromLTRB(720.0, 0.0, 800.0, 600.0));
|
||||
|
||||
expect(find.text('Item 4'), findsNothing);
|
||||
|
||||
// Test shorter weight list.
|
||||
await tester.pumpWidget(buildCarouselView(weights: <int>[7, 1]));
|
||||
await tester.pumpAndSettle();
|
||||
expect(viewportSize, const Size(800, 600));
|
||||
|
||||
expect(find.text('Item 0'), findsOneWidget);
|
||||
rect0 = tester.getRect(getItem(0));
|
||||
// Item width is 7/8 of the viewport.
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 0.0, 700.0, 600.0));
|
||||
|
||||
expect(find.text('Item 1'), findsOneWidget);
|
||||
rect1 = tester.getRect(getItem(1));
|
||||
// Item width is 1/8 of the viewport.
|
||||
expect(rect1, const Rect.fromLTRB(700.0, 0.0, 800.0, 600.0));
|
||||
|
||||
expect(find.text('Item 2'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselController initialItem', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView(
|
||||
controller: controller,
|
||||
controller: CarouselController(initialItem: 5),
|
||||
itemExtent: 400,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
@ -231,6 +289,79 @@ void main() {
|
||||
expect(find.text('Item 7'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects CarouselController.initialItem', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
controller: CarouselController(initialItem: 5),
|
||||
flexWeights: const <int>[7, 1],
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final Size viewportSize = MediaQuery.of(tester.element(find.byType(CarouselView))).size;
|
||||
expect(viewportSize, const Size(800, 600));
|
||||
|
||||
expect(find.text('Item 5'), findsOneWidget);
|
||||
final Rect rect5 = tester.getRect(getItem(5));
|
||||
// Item width is 7/8 of the viewport.
|
||||
expect(rect5, const Rect.fromLTRB(0.0, 0.0, 700.0, 600.0));
|
||||
|
||||
expect(find.text('Item 6'), findsOneWidget);
|
||||
final Rect rect6 = tester.getRect(getItem(6));
|
||||
// Item width is 1/8 of the viewport.
|
||||
expect(rect6, const Rect.fromLTRB(700.0, 0.0, 800.0, 600.0));
|
||||
|
||||
expect(find.text('Item 4'), findsNothing);
|
||||
expect(find.text('Item 7'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('The initialItem should be the first item with expanded size(max extent)', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
controller: CarouselController(initialItem: 5),
|
||||
flexWeights: const <int>[1, 8, 1],
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final Size viewportSize = MediaQuery.of(tester.element(find.byType(CarouselView))).size;
|
||||
expect(viewportSize, const Size(800, 600));
|
||||
|
||||
// Item 5 should have be the expanded item.
|
||||
expect(find.text('Item 5'), findsOneWidget);
|
||||
final Rect rect5 = tester.getRect(getItem(5));
|
||||
// Item width is 8/10 of the viewport.
|
||||
expect(rect5, const Rect.fromLTRB(80.0, 0.0, 720.0, 600.0));
|
||||
|
||||
expect(find.text('Item 6'), findsOneWidget);
|
||||
final Rect rect6 = tester.getRect(getItem(6));
|
||||
// Item width is 1/10 of the viewport.
|
||||
expect(rect6, const Rect.fromLTRB(720.0, 0.0, 800.0, 600.0));
|
||||
|
||||
expect(find.text('Item 4'), findsOneWidget);
|
||||
final Rect rect4 = tester.getRect(getItem(4));
|
||||
// Item width is 1/10 of the viewport.
|
||||
expect(rect4, const Rect.fromLTRB(0.0, 0.0, 80.0, 600.0));
|
||||
|
||||
expect(find.text('Item 7'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView respects itemSnapping', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -279,6 +410,54 @@ void main() {
|
||||
expect(getItem(3), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects itemSnapping', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
itemSnapping: true,
|
||||
consumeMaxWeight: false,
|
||||
flexWeights: const <int>[1, 7],
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
void checkOriginalExpectations() {
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsNothing);
|
||||
}
|
||||
|
||||
checkOriginalExpectations();
|
||||
|
||||
// Snap back to the original item.
|
||||
await tester.drag(getItem(0), const Offset(-20, 0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
checkOriginalExpectations();
|
||||
|
||||
// Snap back to the original item.
|
||||
await tester.drag(getItem(0), const Offset(50, 0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
checkOriginalExpectations();
|
||||
|
||||
// Snap to the next item.
|
||||
await tester.drag(getItem(0), const Offset(-70, 0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsNothing);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView respect itemSnapping when fling', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -333,6 +512,69 @@ void main() {
|
||||
expect(getItem(4), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respect itemSnapping when fling', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
itemSnapping: true,
|
||||
consumeMaxWeight: false,
|
||||
flexWeights: const <int>[1, 8, 1],
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('$index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
Finder getItem(int index)
|
||||
=> find.descendant(
|
||||
of: find.byType(CarouselView),
|
||||
matching: find.ancestor(
|
||||
of: find.text('$index'),
|
||||
matching: find.byType(Padding)
|
||||
),
|
||||
);
|
||||
|
||||
// Show item 0, 1, and 2.
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsNothing);
|
||||
|
||||
// Should snap to item 2 because of a long drag(-100). Show item 2, 3 and 4.
|
||||
await tester.fling(getItem(0), const Offset(-100, 0), 800);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsNothing);
|
||||
expect(getItem(1), findsNothing);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
expect(getItem(4), findsOneWidget);
|
||||
|
||||
// Fling to the next item (item 3). Show item 3, 4 and 5.
|
||||
await tester.fling(getItem(2), const Offset(-50, 0), 800);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(2), findsNothing);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
expect(getItem(4), findsOneWidget);
|
||||
expect(getItem(5), findsOneWidget);
|
||||
|
||||
// Fling back to the previous item. Show item 2, 3 and 4.
|
||||
await tester.fling(getItem(3), const Offset(50, 0), 800);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
expect(getItem(4), findsOneWidget);
|
||||
expect(getItem(5), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView respects scrollingDirection: Axis.vertical', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -367,6 +609,86 @@ void main() {
|
||||
expect(getItem(3), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects scrollingDirection: Axis.vertical', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
flexWeights: const <int>[3, 2, 1],
|
||||
padding: EdgeInsets.zero,
|
||||
scrollDirection: Axis.vertical,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsNothing);
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item width is 3/6 of the viewport.
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 0.0, 800.0, 300.0));
|
||||
|
||||
// Simulate a scroll up
|
||||
await tester.drag(find.byType(CarouselView), const Offset(0, -300), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItem(0), findsNothing);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects scrollingDirection: Axis.vertical + itemSnapping: true', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
itemSnapping: true,
|
||||
flexWeights: const <int>[3, 2, 1],
|
||||
scrollDirection: Axis.vertical,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsNothing);
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item width is 3/6 of the viewport.
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 0.0, 800.0, 300.0));
|
||||
|
||||
// Simulate a scroll up but less than half of the leading item, the leading
|
||||
// item should go back to the original position because itemSnapping is set
|
||||
// to true.
|
||||
await tester.drag(find.byType(CarouselView), const Offset(0, -149), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsNothing);
|
||||
|
||||
// Simulate a scroll up more than half of the leading item, the leading
|
||||
// item continue to scrolling and will disappear when animation ends because
|
||||
// itemSnapping is set to true.
|
||||
await tester.drag(find.byType(CarouselView), const Offset(0, -151), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItem(0), findsNothing);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView respects reverse', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -374,7 +696,6 @@ void main() {
|
||||
body: CarouselView(
|
||||
itemExtent: 200,
|
||||
reverse: true,
|
||||
padding: EdgeInsets.zero,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
@ -407,6 +728,140 @@ void main() {
|
||||
expect(rect3, const Rect.fromLTRB(0.0, 0.0, 200.0, 600.0));
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects reverse', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
flexWeights: const <int>[4, 3, 2, 1],
|
||||
reverse: true,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsOneWidget);
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item 0 should be placed on the end of the screen.
|
||||
const int item0Width = 80 * 4;
|
||||
expect(rect0, const Rect.fromLTRB(800.0 - item0Width, 0.0, 800.0, 600.0));
|
||||
|
||||
expect(getItem(1), findsOneWidget);
|
||||
final Rect rect1 = tester.getRect(getItem(1));
|
||||
// Item 1 should be placed before item 0.
|
||||
const int item1Width = 80 * 3;
|
||||
expect(rect1, const Rect.fromLTRB(800.0 - item0Width - item1Width, 0.0, 800.0 - item0Width, 600.0));
|
||||
|
||||
expect(getItem(2), findsOneWidget);
|
||||
final Rect rect2 = tester.getRect(getItem(2));
|
||||
// Item 2 should be placed before item 1.
|
||||
const int item2Width = 80 * 2;
|
||||
expect(rect2, const Rect.fromLTRB(800.0 - item0Width - item1Width - item2Width, 0.0, 800.0 - item0Width - item1Width, 600.0));
|
||||
|
||||
expect(getItem(3), findsOneWidget);
|
||||
final Rect rect3 = tester.getRect(getItem(3));
|
||||
// Item 3 should be placed before item 2.
|
||||
expect(rect3, const Rect.fromLTRB(0.0, 0.0, 800.0 - item0Width - item1Width - item2Width, 600.0));
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects reverse + vertical scroll direction', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
reverse: true,
|
||||
flexWeights: const <int>[4, 3, 2, 1],
|
||||
scrollDirection: Axis.vertical,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsOneWidget);
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item 0 should be placed on the end of the screen.
|
||||
const int item0Height = 60 * 4;
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 600.0 - item0Height, 800.0, 600.0));
|
||||
|
||||
expect(getItem(1), findsOneWidget);
|
||||
final Rect rect1 = tester.getRect(getItem(1));
|
||||
// Item 1 should be placed before item 0.
|
||||
const int item1Height = 60 * 3;
|
||||
expect(rect1, const Rect.fromLTRB(0.0, 600.0 - item0Height - item1Height, 800.0, 600.0 - item0Height));
|
||||
|
||||
expect(getItem(2), findsOneWidget);
|
||||
final Rect rect2 = tester.getRect(getItem(2));
|
||||
// Item 2 should be placed before item 1.
|
||||
const int item2Height = 60 * 2;
|
||||
expect(rect2, const Rect.fromLTRB(0.0, 600.0 - item0Height - item1Height - item2Height, 800.0, 600.0 - item0Height - item1Height));
|
||||
|
||||
expect(getItem(3), findsOneWidget);
|
||||
final Rect rect3 = tester.getRect(getItem(3));
|
||||
// Item 3 should be placed before item 2.
|
||||
expect(rect3, const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0 - item0Height - item1Height - item2Height));
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects reverse + vertical scroll direction + itemSnapping', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
reverse: true,
|
||||
flexWeights: const <int>[4, 3, 2, 1],
|
||||
scrollDirection: Axis.vertical,
|
||||
itemSnapping: true,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
expect(getItem(4), findsNothing);
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
// Item height is 4/10 of the viewport.
|
||||
expect(rect0, const Rect.fromLTRB(0.0, 360.0, 800.0, 600.0));
|
||||
|
||||
// Simulate a scroll down but less than half of the leading item, the leading
|
||||
// item should go back to the original position because itemSnapping is set
|
||||
// to true.
|
||||
await tester.drag(find.byType(CarouselView), const Offset(0, 240 / 2 - 1), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItem(0), findsOneWidget);
|
||||
expect(getItem(1), findsOneWidget);
|
||||
expect(getItem(2), findsOneWidget);
|
||||
expect(getItem(3), findsOneWidget);
|
||||
expect(getItem(4), findsNothing);
|
||||
|
||||
// Simulate a scroll down more than half of the leading item, the leading
|
||||
// item continue to scrolling and will disappear when animation ends because
|
||||
// itemSnapping is set to true.
|
||||
await tester.drag(find.byType(CarouselView), const Offset(0, 240 / 2 + 1), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItem(0), findsNothing);
|
||||
expect(getItem(4), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CarouselView respects shrinkExtent', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -445,6 +900,240 @@ void main() {
|
||||
await tester.pump();
|
||||
expect(tester.getRect(getItem(0)), const Rect.fromLTRB(-50, 0.0, 250, 600));
|
||||
});
|
||||
|
||||
testWidgets('CarouselView.weighted respects consumeMaxWeight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
flexWeights: const <int>[1, 2, 4, 2, 1],
|
||||
itemSnapping: true,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// The initial item is item 0. To make sure the layout stays the same, the
|
||||
// first item should be placed at the middle of the screen and there are some
|
||||
// white space as if there are two more shinked items before the first item.
|
||||
final Rect rect0 = tester.getRect(getItem(0));
|
||||
expect(rect0, const Rect.fromLTRB(240.0, 0.0, 560.0, 600.0));
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
await tester.drag(find.byType(CarouselView), const Offset(-80.0, 0.0));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
// After scrolling the carousel 7 times, the last item(item 9) should be on
|
||||
// the end of the screen.
|
||||
expect(getItem(9), findsOneWidget);
|
||||
expect(tester.getRect(getItem(9)), const Rect.fromLTRB(720.0, 0.0, 800.0, 600.0));
|
||||
|
||||
// Keep snapping twice. Item 9 should be fully expanded to the max size.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
await tester.drag(find.byType(CarouselView), const Offset(-80.0, 0.0));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
expect(getItem(9), findsOneWidget);
|
||||
expect(tester.getRect(getItem(9)), const Rect.fromLTRB(240.0, 0.0, 560.0, 600.0));
|
||||
});
|
||||
|
||||
testWidgets('The initialItem stays when the flexWeights is updated', (WidgetTester tester) async {
|
||||
final CarouselController controller = CarouselController(initialItem: 3);
|
||||
Widget buildCarousel(List<int> flexWeights) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
controller: controller,
|
||||
flexWeights: flexWeights,
|
||||
itemSnapping: true,
|
||||
children: List<Widget>.generate(20, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildCarousel(<int>[1, 1, 6, 1, 1]));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Item 0'), findsNothing);
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
expect(find.text('Item $i'), findsOneWidget);
|
||||
}
|
||||
Rect rect3 = tester.getRect(getItem(3));
|
||||
expect(rect3.center.dx, 400.0);
|
||||
expect(rect3.center.dy, 300.0);
|
||||
|
||||
expect(find.text('Item 6'), findsNothing);
|
||||
|
||||
await tester.pumpWidget(buildCarousel(<int>[7, 1]));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Item 2'), findsNothing);
|
||||
expect(find.text('Item 3'), findsOneWidget);
|
||||
expect(find.text('Item 4'), findsOneWidget);
|
||||
expect(find.text('Item 5'), findsNothing);
|
||||
|
||||
rect3 = tester.getRect(getItem(3));
|
||||
expect(rect3, const Rect.fromLTRB(0.0, 0.0, 700.0, 600.0));
|
||||
final Rect rect4 = tester.getRect(getItem(4));
|
||||
expect(rect4, const Rect.fromLTRB(700.0, 0.0, 800.0, 600.0));
|
||||
});
|
||||
|
||||
testWidgets('The item that currently occupies max weight stays when the flexWeights is updated', (WidgetTester tester) async {
|
||||
final CarouselController controller = CarouselController(initialItem: 3);
|
||||
Widget buildCarousel(List<int> flexWeights) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
controller: controller,
|
||||
flexWeights: flexWeights,
|
||||
itemSnapping: true,
|
||||
children: List<Widget>.generate(20, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildCarousel(<int>[1, 1, 6, 1, 1]));
|
||||
await tester.pumpAndSettle();
|
||||
// Item 3 is centered.
|
||||
final Rect rect3 = tester.getRect(getItem(3));
|
||||
expect(rect3.center.dx, 400.0);
|
||||
expect(rect3.center.dy, 300.0);
|
||||
|
||||
// Simulate scroll to right and show item 4 to be the centered max item.
|
||||
await tester.drag(find.byType(CarouselView), const Offset(-80.0, 0.0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Item 1'), findsNothing);
|
||||
for (int i = 2; i <= 6; i++) {
|
||||
expect(find.text('Item $i'), findsOneWidget);
|
||||
}
|
||||
Rect rect4 = tester.getRect(getItem(4));
|
||||
expect(rect4.center.dx, 400.0);
|
||||
expect(rect4.center.dy, 300.0);
|
||||
|
||||
await tester.pumpWidget(buildCarousel(<int>[7, 1]));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
rect4 = tester.getRect(getItem(4));
|
||||
expect(rect4, const Rect.fromLTRB(0.0, 0.0, 700.0, 600.0));
|
||||
final Rect rect5 = tester.getRect(getItem(5));
|
||||
expect(rect5, const Rect.fromLTRB(700.0, 0.0, 800.0, 600.0));
|
||||
});
|
||||
|
||||
testWidgets('The initialItem stays when the itemExtent is updated', (WidgetTester tester) async {
|
||||
final CarouselController controller = CarouselController(initialItem: 3);
|
||||
Widget buildCarousel(double itemExtent) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView(
|
||||
controller: controller,
|
||||
itemExtent: itemExtent,
|
||||
itemSnapping: true,
|
||||
children: List<Widget>.generate(20, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildCarousel(234.0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
Offset rect3BottomRight = tester.getRect(getItem(3)).bottomRight;
|
||||
expect(rect3BottomRight.dx, 234.0);
|
||||
expect(rect3BottomRight.dy, 600.0);
|
||||
|
||||
await tester.pumpWidget(buildCarousel(400.0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
rect3BottomRight = tester.getRect(getItem(3)).bottomRight;
|
||||
expect(rect3BottomRight.dx, 400.0);
|
||||
expect(rect3BottomRight.dy, 600.0);
|
||||
|
||||
await tester.pumpWidget(buildCarousel(100.0));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
rect3BottomRight = tester.getRect(getItem(3)).bottomRight;
|
||||
expect(rect3BottomRight.dx, 100.0);
|
||||
expect(rect3BottomRight.dy, 600.0);
|
||||
});
|
||||
|
||||
testWidgets('While scrolling, one extra item will show at the end of the screen during items transition', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CarouselView.weighted(
|
||||
flexWeights: const <int>[1, 2, 4, 2, 1],
|
||||
consumeMaxWeight: false,
|
||||
children: List<Widget>.generate(10, (int index) {
|
||||
return Center(
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
expect(getItem(i), findsOneWidget);
|
||||
}
|
||||
|
||||
// Drag the first item to the middle. So the progress for the first item size change
|
||||
// is 50%, original width is 80.
|
||||
await tester.drag(getItem(0), const Offset(-40.0, 0.0), kind: PointerDeviceKind.trackpad);
|
||||
await tester.pump();
|
||||
expect(tester.getRect(getItem(0)).width, 40.0);
|
||||
|
||||
// The size of item 1 is changing to the size of item 0, so the size of item 1
|
||||
// now should be item1.originalExtent - 50% * (item1.extent - item0.extent).
|
||||
// Item1 originally should be 2/(1+2+4+2+1) * 800 = 160.0.
|
||||
expect(tester.getRect(getItem(1)).width, 160 - 0.5 * (160 - 80));
|
||||
|
||||
// The extent of item 2 should be: item2.originalExtent - 50% * (item2.extent - item1.extent).
|
||||
// the extent of item 2 originally should be 4/(1+2+4+2+1) * 800 = 320.0.
|
||||
expect(tester.getRect(getItem(2)).width, 320 - 0.5 * (320 - 160));
|
||||
|
||||
// The extent of item 3 should be: item3.originalExtent + 50% * (item2.extent - item3.extent).
|
||||
// the extent of item 3 originally should be 2/(1+2+4+2+1) * 800 = 160.0.
|
||||
expect(tester.getRect(getItem(3)).width, 160 + 0.5 * (320 - 160));
|
||||
|
||||
// The extent of item 4 should be: item4.originalExtent + 50% * (item3.extent - item4.extent).
|
||||
// the extent of item 4 originally should be 1/(1+2+4+2+1) * 800 = 80.0.
|
||||
expect(tester.getRect(getItem(4)).width, 80 + 0.5 * (160 - 80));
|
||||
|
||||
// The sum of the first 5 items during transition is less than the screen width.
|
||||
double sum = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sum += tester.getRect(getItem(i)).width;
|
||||
}
|
||||
expect(sum, lessThan(MediaQuery.of(tester.element(find.byType(CarouselView))).size.width));
|
||||
final double difference = MediaQuery.of(tester.element(find.byType(CarouselView))).size.width - sum;
|
||||
|
||||
// One more item should show on screen to fill the rest of the viewport.
|
||||
expect(getItem(5), findsOneWidget);
|
||||
expect(tester.getRect(getItem(5)).width, difference);
|
||||
});
|
||||
}
|
||||
|
||||
Finder getItem(int index) {
|
||||
|
Loading…
Reference in New Issue
Block a user