From 505aaa667abff16a42d1ceae6a8dd91cda34ff36 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 30 Aug 2022 18:47:21 -0400 Subject: [PATCH] Revert "[dynamic_layouts] Add Wrap layout and updates to the README (#2513)" (#2534) This reverts commit a2e65e9656a018692be2adc4f3e2d689b82adea5. --- packages/dynamic_layouts/README.md | 131 +--- .../dynamic_layouts/lib/dynamic_layouts.dart | 1 - .../lib/src/base_grid_layout.dart | 11 +- .../dynamic_layouts/lib/src/dynamic_grid.dart | 74 +- .../dynamic_layouts/lib/src/wrap_layout.dart | 268 -------- .../test/base_grid_layout_test.dart | 4 +- .../test/dynamic_grid_test.dart | 15 +- .../test/wrap_layout_test.dart | 636 ------------------ 8 files changed, 27 insertions(+), 1113 deletions(-) delete mode 100644 packages/dynamic_layouts/lib/src/wrap_layout.dart delete mode 100644 packages/dynamic_layouts/test/wrap_layout_test.dart diff --git a/packages/dynamic_layouts/README.md b/packages/dynamic_layouts/README.md index 0973efacd2..fc7bdab71d 100644 --- a/packages/dynamic_layouts/README.md +++ b/packages/dynamic_layouts/README.md @@ -13,138 +13,25 @@ and the Flutter guide for [developing packages and plugins](https://flutter.dev/developing-packages). --> - +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. ## Features -This package provides support for multi sized tiles and different layouts. -Currently the layouts that are implemented in this package are `Stagger` and -`Wrap`. -The following are some demos of how each of the grids look. - -A stagger grid demo: - - - -A wrap demo: - - - -### Stagger Features - -`DynamicGridView` is a subclass of `GridView` and gives access -to the `SliverGridDelegate`s that are already implemented in the Flutter -Framework. Some `SliverGridDelegate`s are `SliverGridDelegateWithMaxCrossAxisExtent` and -`SliverGridDelegateWithFixedCrossAxisCount`. This layout can be used with -`DynamicGridView.stagger`. - -### Wrap Features - -The Wrap layout is able to do runs of different widgets and adapt accordingly with -the sizes of the children. It can leave spacing with `mainAxisSpacing` and -`crossAxisSpacing`. - -Having different sizes in only one of the axis is possible by -changing the values of `childCrossAxisExtent` and `childMainAxisExtent`. These -values by default are set to have loose constraints, but by giving `childCrossAxisExtent` a specific value like -100 pixels, it will make all of the children 100 pixels in the main axis. -This layout can be used with `DynamicGridView.wrap` and with -`DynamicGridView.builder` and `SliverGridDelegateWithWrapping` as the delegate. +TODO: List what your package can do. Maybe include images, gifs, or videos. ## Getting started - +TODO: List prerequisites and provide or point to information on how to +start using the package. ## Usage -Use `DynamicGridView`s to access this layouts. -`DynamicGridView` has some constructors that use `SliverChildListDelegate` like -`.wrap` and `.stagger`. For a more efficient option that uses `SliverChildBuilderDelegate` use -`.builder`, it works the same as `GridView.builder`. - -### Wrap - -The following are simple examples of how to use `DynamicGridView.wrap`. - - -```dart -final List children = List.generate( - 250, - (index) => Container( - height: index.isEven ? 100 : 50, - width: index.isEven ? 95 : 180, - color: index.isEven ? Colors.red : Colors.blue, - child: Center(child: Text('Item $index')), - ), - ); - -DynamicGridView.wrap( - mainAxisSpacing: 10, - crossAxisSpacing: 20, - children: children, -); -``` - -The following example uses `DynamicGridView.builder` with -`SliverGridDelegateWithWrapping`. - - -```dart -DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping( - mainAxisSpacing: 20, - childMainAxisExtent: 250, - childCrossAxisExtent: 50, - ), - itemBuilder: (BuildContext context, int index) { - return Container( - height: 200, - color: index.isEven ? Colors.amber : Colors.blue, - child: Center( - child: Text('$index'), - ), - ); - }, - ), -``` - -By using `childCrossAxisExtent` and `childMainAxisExtent` the main axis -can be limited to have a specific size and the other can be set to loose -constraints. - - -```dart -DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping( - mainAxisSpacing: 20, - childMainAxisExtent: 250, - ), - itemBuilder: (BuildContext context, int index) { - return Container( - height: 200, - color: index.isEven ? Colors.amber : Colors.blue, - child: Center( - child: Text('$index'), - ), - ); - }, -), -``` - -### Stagger - -The `Stagger` layout can be used with the constructor -`DynamicGridView.stagger` and still use the delegates from `GridView` -like `SliverGridDelegateWithMaxCrossAxisExtent` and -`SliverGridDelegateWithFixedCrossAxisCount`. - - - - +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. ## Additional information - +from the package authors, and more. diff --git a/packages/dynamic_layouts/lib/dynamic_layouts.dart b/packages/dynamic_layouts/lib/dynamic_layouts.dart index ad714663fb..3f3537490e 100644 --- a/packages/dynamic_layouts/lib/dynamic_layouts.dart +++ b/packages/dynamic_layouts/lib/dynamic_layouts.dart @@ -5,4 +5,3 @@ export 'src/base_grid_layout.dart'; export 'src/dynamic_grid.dart'; export 'src/render_dynamic_grid.dart'; -export 'src/wrap_layout.dart'; diff --git a/packages/dynamic_layouts/lib/src/base_grid_layout.dart b/packages/dynamic_layouts/lib/src/base_grid_layout.dart index e33e7d6a80..0c6b6bae18 100644 --- a/packages/dynamic_layouts/lib/src/base_grid_layout.dart +++ b/packages/dynamic_layouts/lib/src/base_grid_layout.dart @@ -37,14 +37,14 @@ class DynamicSliverGridGeometry extends SliverGridGeometry { crossAxisExtent.isInfinite ? 0.0 : crossAxisExtent; switch (constraints.axis) { - case Axis.vertical: + case Axis.horizontal: return BoxConstraints( minHeight: mainMinExtent, maxHeight: mainAxisExtent, minWidth: crossMinExtent, maxWidth: crossAxisExtent, ); - case Axis.horizontal: + case Axis.vertical: return BoxConstraints( minHeight: crossMinExtent, maxHeight: crossAxisExtent, @@ -68,17 +68,14 @@ abstract class DynamicSliverGridLayout extends SliverGridLayout { /// provide looser constraints to the child, whose size after layout can be /// reported back to the layout object in [updateGeometryForChildIndex]. @override - DynamicSliverGridGeometry getGeometryForChildIndex(int index); + SliverGridGeometry getGeometryForChildIndex(int index); /// Update the size and position of the child with the given index, /// considering the size of the child after layout. /// /// This is used to update the layout object after the child has laid out, /// allowing the layout pattern to adapt to the child's size. - DynamicSliverGridGeometry updateGeometryForChildIndex( - int index, - Size childSize, - ); + SliverGridGeometry updateGeometryForChildIndex(int index, Size childSize); /// Called by [RenderDynamicSliverGrid] to validate the layout pattern has /// filled the screen. diff --git a/packages/dynamic_layouts/lib/src/dynamic_grid.dart b/packages/dynamic_layouts/lib/src/dynamic_grid.dart index a9aceccd50..9649a3ff3a 100644 --- a/packages/dynamic_layouts/lib/src/dynamic_grid.dart +++ b/packages/dynamic_layouts/lib/src/dynamic_grid.dart @@ -5,7 +5,6 @@ import 'package:flutter/widgets.dart'; import 'render_dynamic_grid.dart'; -import 'wrap_layout.dart'; /// A scrollable, 2D array of widgets. /// @@ -13,10 +12,13 @@ import 'wrap_layout.dart'; class DynamicGridView extends GridView { /// Creates a scrollable, 2D array of widgets with a custom /// [SliverGridDelegate]. + /// + // TODO(all): what other parameters should we add to these + // constructors, here, builder, etc.? + // + reverse + // + scrollDirection DynamicGridView({ super.key, - super.scrollDirection, - super.reverse, required super.gridDelegate, // This creates a SliverChildListDelegate in the super class. super.children = const [], @@ -25,77 +27,13 @@ class DynamicGridView extends GridView { /// Creates a scrollable, 2D array of widgets that are created on demand. DynamicGridView.builder({ super.key, - super.scrollDirection, - super.reverse, required super.gridDelegate, // This creates a SliverChildBuilderDelegate in the super class. required super.itemBuilder, super.itemCount, }) : super.builder(); - /// Creates a scrollable, 2D array of widgets with tiles where each tile can - /// have its own size. - /// - /// Uses a [SliverGridDelegateWithWrapping] as the [gridDelegate]. - /// - /// The following example shows how to use the DynamicGridView.wrap constructor. - /// - /// ```dart - /// DynamicGridView.wrap( - /// mainAxisSpacing: 10, - /// crossAxisSpacing: 20, - /// children: [ - /// Container( - /// height: 100, - /// width: 200, - /// color: Colors.amberAccent[100], - /// child: const Center(child: Text('Item 1') - /// ), - /// ), - /// Container( - /// height: 50, - /// width: 70, - /// color: Colors.blue[100], - /// child: const Center(child: Text('Item 2'), - /// ), - /// ), - /// Container( - /// height: 82, - /// width: 300, - /// color: Colors.pink[100], - /// child: const Center(child: Text('Item 3'), - /// ), - /// ), - /// Container( - /// color: Colors.green[100], - /// child: const Center(child: Text('Item 3'), - /// ), - /// ), - /// ], - /// ), - /// ``` - /// - /// See also: - /// - /// * [SliverGridDelegateWithWrapping] to see a more detailed explanation of - /// how the wrapping works. - DynamicGridView.wrap({ - super.key, - super.scrollDirection, - super.reverse, - double mainAxisSpacing = 0.0, - double crossAxisSpacing = 0.0, - double childCrossAxisExtent = double.infinity, - double childMainAxisExtent = double.infinity, - super.children = const [], - }) : super( - gridDelegate: SliverGridDelegateWithWrapping( - mainAxisSpacing: mainAxisSpacing, - crossAxisSpacing: crossAxisSpacing, - childCrossAxisExtent: childCrossAxisExtent, - childMainAxisExtent: childMainAxisExtent, - ), - ); + // TODO(snat-s): DynamicGridView.wrap? // TODO(DavBot09): DynamicGridView.stagger? diff --git a/packages/dynamic_layouts/lib/src/wrap_layout.dart b/packages/dynamic_layouts/lib/src/wrap_layout.dart deleted file mode 100644 index 2a13173803..0000000000 --- a/packages/dynamic_layouts/lib/src/wrap_layout.dart +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2013 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/rendering.dart'; - -import 'base_grid_layout.dart'; - -// The model that tracks the current max size of the Sliver in the mainAxis and -// tracks if there is still space on the crossAxis. -class _RunMetrics { - _RunMetrics({ - required this.maxSliver, - required this.currentSizeUsed, - required this.scrollOffset, - }); - - /// The biggest sliver size for the current run. - double maxSliver; - - /// The current size that has been used in the current run. - double currentSizeUsed; - - /// The scroll offset in the current run. - double scrollOffset; -} - -/// A [DynamicSliverGridLayout] that uses dynamically sized tiles. -/// -/// Rather that providing a grid with a [DynamicSliverGridLayout] directly, instead -/// provide the grid a [SliverGridDelegate], which can compute a -/// [DynamicSliverGridLayout] given the current [SliverConstraints]. -/// -/// This layout is used by [SliverGridDelegateWithWrapping]. -/// -/// See also: -/// -/// * [SliverGridDelegateWithWrapping], which uses this layout. -/// * [DynamicSliverGridLayout], which represents an arbitrary dynamic tile layout. -/// * [DynamicSliverGridGeometry], which represents the size and position of a -/// single tile in a grid. -/// * [SliverGridDelegate.getLayout], which returns this object to describe the -/// delegate's layout. -/// * [RenderDynamicSliverGrid], which uses this class during its -/// [RenderDynamicSliverGrid.performLayout] method. -class SliverGridWrappingTileLayout extends DynamicSliverGridLayout { - /// Creates a layout that uses dynamic sized and spaced tiles. - /// - /// All of the arguments must not be null and must not be negative. - SliverGridWrappingTileLayout({ - required this.mainAxisSpacing, - required this.crossAxisSpacing, - required this.childMainAxisExtent, - required this.childCrossAxisExtent, - required this.crossAxisExtent, - required this.scrollDirection, - }) : assert(mainAxisSpacing != null && mainAxisSpacing >= 0), - assert(crossAxisSpacing != null && crossAxisSpacing >= 0), - assert(childMainAxisExtent != null && childMainAxisExtent >= 0), - assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0), - assert(crossAxisExtent != null && crossAxisExtent >= 0), - assert(scrollDirection != null && - (scrollDirection == Axis.horizontal || - scrollDirection == Axis.vertical)); - - /// The direction in wich the layout should be built. - final Axis scrollDirection; - - /// The extent of the child in the non-scrolling axis. - final double crossAxisExtent; - - /// The number of logical pixels between each child along the main axis. - final double mainAxisSpacing; - - /// The number of logical pixels between each child along the cross axis. - final double crossAxisSpacing; - - /// The number of pixels from the leading edge of one tile to the trailing - /// edge of the same tile in the main axis. - final double childMainAxisExtent; - - /// The number of pixels from the leading edge of one tile to the trailing - /// edge of the same tile in the cross axis. - final double childCrossAxisExtent; - - /// The model that is used internally to keep track of how much space is left - /// and how much has been used. - final List<_RunMetrics> _model = <_RunMetrics>[ - _RunMetrics(maxSliver: 0.0, currentSizeUsed: 0.0, scrollOffset: 0.0) - ]; - - // This method provides the initial constraints for the child to layout, - // and then it is updated with the final size later in - // updateGeometryForChildIndex. - @override - DynamicSliverGridGeometry getGeometryForChildIndex(int index) { - return DynamicSliverGridGeometry( - scrollOffset: 0, - crossAxisOffset: 0, - mainAxisExtent: childMainAxisExtent, - crossAxisExtent: childCrossAxisExtent, - ); - } - - @override - DynamicSliverGridGeometry updateGeometryForChildIndex( - int index, - Size childSize, - ) { - final double scrollOffset = _model.last.scrollOffset; - final double currentSizeUsed = _model.last.currentSizeUsed; - late final double addedSize; - - switch (scrollDirection) { - case Axis.vertical: - addedSize = currentSizeUsed + childSize.width + crossAxisSpacing; - break; - case Axis.horizontal: - addedSize = currentSizeUsed + childSize.height + mainAxisSpacing; - break; - } - - if (addedSize > crossAxisExtent && _model.last.currentSizeUsed > 0.0) { - switch (scrollDirection) { - case Axis.vertical: - _model.add( - _RunMetrics( - maxSliver: childSize.height + mainAxisSpacing, - currentSizeUsed: childSize.width + crossAxisSpacing, - scrollOffset: - scrollOffset + _model.last.maxSliver + mainAxisSpacing, - ), - ); - break; - case Axis.horizontal: - _model.add( - _RunMetrics( - maxSliver: childSize.width + crossAxisSpacing, - currentSizeUsed: childSize.height + mainAxisSpacing, - scrollOffset: - scrollOffset + _model.last.maxSliver + crossAxisSpacing, - ), - ); - break; - } - - return DynamicSliverGridGeometry( - scrollOffset: _model.last.scrollOffset, - crossAxisOffset: 0.0, - mainAxisExtent: childSize.height + mainAxisSpacing, - crossAxisExtent: childSize.width + crossAxisSpacing, - ); - } else { - _model.last.currentSizeUsed = addedSize; - } - - switch (scrollDirection) { - case Axis.vertical: - if (childSize.height + mainAxisSpacing > _model.last.maxSliver) { - _model.last.maxSliver = childSize.height + mainAxisSpacing; - } - break; - case Axis.horizontal: - if (childSize.width + crossAxisSpacing > _model.last.maxSliver) { - _model.last.maxSliver = childSize.width + crossAxisSpacing; - } - break; - } - - return DynamicSliverGridGeometry( - scrollOffset: scrollOffset, - crossAxisOffset: currentSizeUsed, - mainAxisExtent: childSize.height, - crossAxisExtent: childSize.width, - ); - } - - @override - bool reachedTargetScrollOffset(double targetOffset) { - return _model.last.scrollOffset > targetOffset; - } -} - -/// A [SliverGridDelegate] for creating grids that wrap variably sized tiles. -/// -/// For example, if the grid is vertical, this delegate will create a layout -/// where the children are layed out until they fill the horizontal axis and then -/// they continue in the next row. If the grid is horizontal, this delegate will -/// do the same but it will fill the vertical axis and will pass to another -/// column until it finishes. -/// -/// This delegate creates grids with different sized tiles. Tiles -/// can have fixed dimensions if [childCrossAxisExtent] or -/// [childMainAxisExtent] are provided. -/// -/// See also: -/// * [DynamicGridView.wrap], wich is a constructor to use this [SliverGridDelegate], -/// like `GridView.extent`. -/// * [DynamicGridView], which can use this delegate to control the layout of its -/// tiles. -/// * [RenderDynamicSliverGrid], which can use this delegate to control the -/// layout of its tiles. -class SliverGridDelegateWithWrapping extends SliverGridDelegate { - /// Create a delegate that wraps variably sized tiles. - /// - /// The children widgets are provided with loose constraints, and if any of the - /// extent parameters are set, the children are given tight constraints. - /// The way that children are made to have loose constraints is by assigning - /// the value of [double.infinity] to [childMainAxisExtent] and - /// [childCrossAxisExtent]. - /// To have same sized tiles with the wrapping, specify the [childCrossAxisExtent] - /// and the [childMainAxisExtent] to be the same size. Or only one of them to - /// be of a certain size in one of the axis. - const SliverGridDelegateWithWrapping({ - this.mainAxisSpacing = 0.0, - this.crossAxisSpacing = 0.0, - this.childCrossAxisExtent = double.infinity, - this.childMainAxisExtent = double.infinity, - }) : assert(mainAxisSpacing != null && mainAxisSpacing >= 0), - assert(crossAxisSpacing != null && crossAxisSpacing >= 0); - - /// The number of pixels from the leading edge of one tile to the trailing - /// edge of the same tile in the main axis. - /// - /// Defaults to [double.infinity] to provide the child with loose constraints. - final double childMainAxisExtent; - - /// The number of pixels from the leading edge of one tile to the trailing - /// edge of the same tile in the cross axis. - /// - /// Defaults to [double.infinity] to provide the child with loose constraints. - final double childCrossAxisExtent; - - /// The number of logical pixels between each child along the main axis. - /// - /// Defaults to 0.0 - final double mainAxisSpacing; - - /// The number of logical pixels between each child along the cross axis. - /// - /// Defaults to 0.0 - final double crossAxisSpacing; - - bool _debugAssertIsValid() { - assert(mainAxisSpacing >= 0.0); - assert(crossAxisSpacing >= 0.0); - return true; - } - - @override - SliverGridLayout getLayout(SliverConstraints constraints) { - assert(_debugAssertIsValid()); - return SliverGridWrappingTileLayout( - childMainAxisExtent: childMainAxisExtent, - childCrossAxisExtent: childCrossAxisExtent, - mainAxisSpacing: mainAxisSpacing, - crossAxisSpacing: crossAxisSpacing, - scrollDirection: axisDirectionToAxis(constraints.axisDirection), - crossAxisExtent: constraints.crossAxisExtent, - ); - } - - @override - bool shouldRelayout(SliverGridDelegateWithWrapping oldDelegate) { - return oldDelegate.mainAxisSpacing != mainAxisSpacing || - oldDelegate.crossAxisSpacing != crossAxisSpacing; - } -} diff --git a/packages/dynamic_layouts/test/base_grid_layout_test.dart b/packages/dynamic_layouts/test/base_grid_layout_test.dart index 59e6bd5564..69638e8298 100644 --- a/packages/dynamic_layouts/test/base_grid_layout_test.dart +++ b/packages/dynamic_layouts/test/base_grid_layout_test.dart @@ -12,8 +12,8 @@ void main() { const DynamicSliverGridGeometry geometry = DynamicSliverGridGeometry( scrollOffset: 0, crossAxisOffset: 0, - crossAxisExtent: 150.0, - mainAxisExtent: 50.0, + mainAxisExtent: 150.0, + crossAxisExtent: 50.0, ); // Vertical diff --git a/packages/dynamic_layouts/test/dynamic_grid_test.dart b/packages/dynamic_layouts/test/dynamic_grid_test.dart index 52b17dd37e..e6ad3300ae 100644 --- a/packages/dynamic_layouts/test/dynamic_grid_test.dart +++ b/packages/dynamic_layouts/test/dynamic_grid_test.dart @@ -38,7 +38,7 @@ void main() { ), ); - // Only the visible tiles have been laid out. + // Only the visible tiles have ben laid out. expect(find.text('Index 0'), findsOneWidget); expect(tester.getTopLeft(find.text('Index 0')), Offset.zero); expect(find.text('Index 1'), findsOneWidget); @@ -69,7 +69,7 @@ void main() { ), ); - // Only the visible tiles have been laid out, up to itemCount. + // Only the visible tiles have ben laid out, up to itemCount. expect(find.text('Index 0'), findsOneWidget); expect(tester.getTopLeft(find.text('Index 0')), Offset.zero); expect(find.text('Index 1'), findsOneWidget); @@ -119,9 +119,9 @@ class TestSimpleLayout extends DynamicSliverGridLayout { static const double childExtent = 50.0; @override - DynamicSliverGridGeometry getGeometryForChildIndex(int index) { + SliverGridGeometry getGeometryForChildIndex(int index) { final double crossAxisStart = (index % crossAxisCount) * childExtent; - return DynamicSliverGridGeometry( + return SliverGridGeometry( scrollOffset: (index ~/ crossAxisCount) * childExtent, crossAxisOffset: crossAxisStart, mainAxisExtent: childExtent, @@ -133,10 +133,7 @@ class TestSimpleLayout extends DynamicSliverGridLayout { bool reachedTargetScrollOffset(double targetOffset) => true; @override - DynamicSliverGridGeometry updateGeometryForChildIndex( - int index, - Size childSize, - ) { + SliverGridGeometry updateGeometryForChildIndex(int index, Size childSize) { return getGeometryForChildIndex(index); } } @@ -145,7 +142,7 @@ class TestDelegate extends SliverGridDelegateWithFixedCrossAxisCount { TestDelegate({required super.crossAxisCount}); @override - DynamicSliverGridLayout getLayout(SliverConstraints constraints) { + SliverGridLayout getLayout(SliverConstraints constraints) { return TestSimpleLayout(crossAxisCount: crossAxisCount); } } diff --git a/packages/dynamic_layouts/test/wrap_layout_test.dart b/packages/dynamic_layouts/test/wrap_layout_test.dart deleted file mode 100644 index d595fe75df..0000000000 --- a/packages/dynamic_layouts/test/wrap_layout_test.dart +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright 2013 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:dynamic_layouts/dynamic_layouts.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets( - 'DynamicGridView generates children and checks if they are layed out', - (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 95 : 180, - child: Text('Item $index'), - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView( - gridDelegate: const SliverGridDelegateWithWrapping(), - children: children, - ), - ), - ), - ); - - // Check that the children are in the tree - for (int i = 0; i < 10; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // Check that the children are in the right position - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 5')), const Offset(0.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 6')), const Offset(180.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 7')), const Offset(275.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 8')), const Offset(455.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 9')), const Offset(550.0, 100.0)); - }); - - testWidgets( - 'Test for wrap that generates children and checks if they are layed out', - (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 95 : 180, - child: Text('Item $index'), - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.wrap( - children: children, - ), - ), - ), - ); - for (int i = 0; i < 10; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // Check that the children are in the right position - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 5')), const Offset(0.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 6')), const Offset(180.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 7')), const Offset(275.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 8')), const Offset(455.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 9')), const Offset(550.0, 100.0)); - }); - - testWidgets('Test for wrap to be laying child dynamically', - (WidgetTester tester) async { - final List children = List.generate( - 20, - (int index) => SizedBox( - height: index.isEven ? 1000 : 50, - width: index.isEven ? 95 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - itemCount: children.length, - gridDelegate: const SliverGridDelegateWithWrapping(), - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - for (int i = 0; i < 5; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // Check that the children are in the right position - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(95.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(275.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(370.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 4')), const Offset(550.0, 0.0)); - expect(find.text('Item 5'), findsNothing); - await tester.scrollUntilVisible(find.text('Item 19'), 500.0); - await tester.pumpAndSettle(); - - expect(find.text('Item 18'), findsOneWidget); - expect(tester.getTopLeft(find.text('Item 18')), const Offset(455.0, 0.0)); - - expect(find.text('Item 0'), findsNothing); - expect(find.text('Item 1'), findsNothing); - expect(find.text('Item 2'), findsNothing); - expect(find.text('Item 3'), findsNothing); - }); - - testWidgets( - 'Test for DynamicGridView.wrap to scrollDirection Axis.horizontal', - (WidgetTester tester) async { - final List children = List.generate( - 20, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.wrap( - scrollDirection: Axis.horizontal, - children: children, - ), - ), - ), - ); - for (int i = 0; i < 20; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // Check that the children are in the right position - double dy = 0, dx = 0; - for (int i = 0; i < 20; i++) { - if (dy >= 600.0) { - dy = 0.0; - dx += 180.0; - } - expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy)); - dy += i.isEven ? 100 : 50; - } - }); - - testWidgets('Test DynamicGridView.builder for GridView.reverse to true', - (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - reverse: true, - itemCount: children.length, - gridDelegate: const SliverGridDelegateWithWrapping(), - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - for (int i = 0; i < 10; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - double dx = 0.0, dy = 600.0; - for (int i = 0; i < 10; i++) { - if (dx >= 600.0) { - dx = 0.0; - dy -= 100.0; - } - expect(tester.getBottomLeft(find.text('Item $i')), Offset(dx, dy)); - dx += i.isEven ? 100 : 180; - } - }); - - testWidgets('DynamicGridView.wrap for GridView.reverse to true', - (WidgetTester tester) async { - final List children = List.generate( - 20, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.wrap( - reverse: true, - children: children, - ), - ), - ), - ); - for (int i = 0; i < 20; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // Check that the children are in the right position - double dx = 0.0, dy = 600.0; - for (int i = 0; i < 20; i++) { - if (dx >= 600.0) { - dx = 0.0; - dy -= 100.0; - } - expect(tester.getBottomLeft(find.text('Item $i')), Offset(dx, dy)); - dx += i.isEven ? 100 : 180; - } - }); - - testWidgets('DynamicGridView.wrap dismiss keyboard onDrag test', - (WidgetTester tester) async { - final List focusNodes = - List.generate(50, (int i) => FocusNode()); - - await tester.pumpWidget( - textFieldBoilerplate( - child: GridView.extent( - padding: EdgeInsets.zero, - maxCrossAxisExtent: 300, - keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, - children: focusNodes.map((FocusNode focusNode) { - return Container( - height: 50, - color: Colors.green, - child: TextField( - focusNode: focusNode, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - ); - }).toList(), - ), - ), - ); - - final Finder finder = find.byType(TextField).first; - final TextField textField = tester.widget(finder); - await tester.showKeyboard(finder); - expect(textField.focusNode!.hasFocus, isTrue); - - await tester.drag(finder, const Offset(0.0, -40.0)); - await tester.pumpAndSettle(); - expect(textField.focusNode!.hasFocus, isFalse); - }); - - testWidgets('ChildMainAxisExtent & childCrossAxisExtent are respected', - (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - key: Key(index.toString()), - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping( - childMainAxisExtent: 150, - childCrossAxisExtent: 200, - ), - itemCount: children.length, - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - - for (int i = 0; i < 10; i++) { - final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i'))); - expect(sizeOfCurrent.width, equals(200)); - expect(sizeOfCurrent.height, equals(150)); - } - // Check that the children are in the right position - double dy = 0, dx = 0; - for (int i = 0; i < 10; i++) { - if (dx > 600.0) { - dx = 0.0; - dy += 150.0; - } - expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy)); - dx += 200; - } - }); - - testWidgets('ChildMainAxisExtent is respected', (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - key: Key(index.toString()), - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping( - childMainAxisExtent: 200, - ), - itemCount: children.length, - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - - for (int i = 0; i < 10; i++) { - final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i'))); - expect(sizeOfCurrent.height, equals(200)); - } - // Check that the children are in the right position - double dy = 0, dx = 0; - for (int i = 0; i < 10; i++) { - if (dx >= 600.0) { - dx = 0.0; - dy += 200.0; - } - expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy)); - dx += i.isEven ? 100 : 180; - } - }); - - testWidgets('ChildCrossAxisExtent is respected', (WidgetTester tester) async { - final List children = List.generate( - 10, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - key: Key(index.toString()), - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping( - childCrossAxisExtent: 150, - ), - itemCount: children.length, - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - - for (int i = 0; i < 10; i++) { - final Size sizeOfCurrent = tester.getSize(find.byKey(Key('$i'))); - expect(sizeOfCurrent.width, equals(150)); - } - // Check that the children are in the right position - double dy = 0, dx = 0; - for (int i = 0; i < 10; i++) { - if (dx >= 750.0) { - dx = 0.0; - dy += 100.0; - } - expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy)); - dx += 150; - } - }); - - testWidgets('Test wrap to see nothing affected if elements are deleted.', - (WidgetTester tester) async { - late StateSetter stateSetter; - final List children = List.generate( - 10, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - stateSetter = setState; - return DynamicGridView.builder( - gridDelegate: const SliverGridDelegateWithWrapping(), - itemCount: children.length, - itemBuilder: (BuildContext context, int index) => children[index], - ); - }), - ), - ), - ); - // See if the children are in the tree. - for (int i = 0; i < 10; i++) { - expect(find.text('Item $i'), findsOneWidget); - } - // See if they are layed properly. - double dx = 0.0, dy = 0.0; - for (int i = 0; i < 10; i++) { - if (dx >= 600) { - dx = 0.0; - dy += 100; - } - expect(tester.getTopLeft(find.text('Item $i')), Offset(dx, dy)); - dx += i.isEven ? 100 : 180; - } - stateSetter(() { - // Remove children - children.removeAt(0); - children.removeAt(8); - children.removeAt(5); - }); - - await tester.pump(); - - // See if the proper widgets are in the tree. - expect(find.text('Item 0'), findsNothing); - expect(find.text('Item 6'), findsNothing); - expect(find.text('Item 9'), findsNothing); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 2'), findsOneWidget); - expect(find.text('Item 3'), findsOneWidget); - expect(find.text('Item 4'), findsOneWidget); - expect(find.text('Item 5'), findsOneWidget); - expect(find.text('Item 7'), findsOneWidget); - expect(find.text('Item 8'), findsOneWidget); - - // See if the proper widgets are in the tree. - expect(tester.getTopLeft(find.text('Item 1')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(180.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(280.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 4')), const Offset(460.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 5')), const Offset(560.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 7')), const Offset(0.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 8')), const Offset(180.0, 100.0)); - }); - - testWidgets('Test wrap in Axis.vertical direction', - (WidgetTester tester) async { - final List children = List.generate( - 5, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.builder( - itemCount: children.length, - gridDelegate: const SliverGridDelegateWithWrapping(), - itemBuilder: (BuildContext context, int index) => children[index], - ), - ), - ), - ); - - // Change the size of the screen - await tester.binding.setSurfaceSize(const Size(500, 100)); - await tester.pumpAndSettle(); - expect(find.text('Item 0'), findsOneWidget); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 2'), findsOneWidget); - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(280.0, 0.0)); - expect(find.text('Item 3'), findsNothing); - expect(find.text('Item 4'), findsNothing); - await tester.binding.setSurfaceSize(const Size(560, 100)); - await tester.pumpAndSettle(); - expect(find.text('Item 3'), findsOneWidget); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(380.0, 0.0)); - expect(find.text('Item 4'), findsNothing); - await tester.binding.setSurfaceSize(const Size(280, 100)); - // resets the screen to its original size after the test end - addTearDown(tester.binding.window.clearPhysicalSizeTestValue); - await tester.pumpAndSettle(); - expect(find.text('Item 0'), findsOneWidget); - expect(find.text('Item 1'), findsOneWidget); - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0)); - expect(find.text('Item 2'), findsNothing); - expect(find.text('Item 3'), findsNothing); - expect(find.text('Item 4'), findsNothing); - }); - - testWidgets('Test wrap in Axis.horizontal direction', - (WidgetTester tester) async { - final List children = List.generate( - 5, - (int index) => SizedBox( - height: index.isEven ? 100 : 50, - width: index.isEven ? 100 : 180, - child: Text('Item $index'), - ), - ); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: DynamicGridView.wrap( - scrollDirection: Axis.horizontal, - children: children, - ), - ), - ), - ); - - // Change the size of the screen - await tester.binding.setSurfaceSize(const Size(180, 150)); - await tester.pumpAndSettle(); - - expect(find.text('Item 0'), findsOneWidget); - expect(find.text('Item 1'), findsOneWidget); - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(0.0, 100.0)); - - expect(find.text('Item 2'), findsNothing); - expect(find.text('Item 3'), findsNothing); - - await tester.binding.setSurfaceSize(const Size(180, 400)); - await tester.pumpAndSettle(); - - expect(find.text('Item 0'), findsOneWidget); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 2'), findsOneWidget); - expect(find.text('Item 3'), findsOneWidget); - expect(find.text('Item 4'), findsOneWidget); - - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(0.0, 100.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(0.0, 150.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(0.0, 250.0)); - expect(tester.getTopLeft(find.text('Item 4')), const Offset(0.0, 300.0)); - - await tester.binding.setSurfaceSize(const Size(560, 100)); - // resets the screen to its original size after the test end - addTearDown(tester.binding.window.clearPhysicalSizeTestValue); - await tester.pumpAndSettle(); - - expect(find.text('Item 0'), findsOneWidget); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 2'), findsOneWidget); - expect(find.text('Item 3'), findsOneWidget); - expect(find.text('Item 4'), findsNothing); - - expect(tester.getTopLeft(find.text('Item 0')), const Offset(0.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 1')), const Offset(100.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 2')), const Offset(280.0, 0.0)); - expect(tester.getTopLeft(find.text('Item 3')), const Offset(380.0, 0.0)); - }); -} - -Widget textFieldBoilerplate({required Widget child}) { - return MaterialApp( - home: Localizations( - locale: const Locale('en', 'US'), - delegates: >[ - WidgetsLocalizationsDelegate(), - MaterialLocalizationsDelegate(), - ], - child: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(size: Size(800.0, 600.0)), - child: Center( - child: Material( - child: child, - ), - ), - ), - ), - ), - ); -} - -class MaterialLocalizationsDelegate - extends LocalizationsDelegate { - @override - bool isSupported(Locale locale) => true; - - @override - Future load(Locale locale) => - DefaultMaterialLocalizations.load(locale); - - @override - bool shouldReload(MaterialLocalizationsDelegate old) => false; -} - -class WidgetsLocalizationsDelegate - extends LocalizationsDelegate { - @override - bool isSupported(Locale locale) => true; - - @override - Future load(Locale locale) => - DefaultWidgetsLocalizations.load(locale); - - @override - bool shouldReload(WidgetsLocalizationsDelegate old) => false; -}