mirror of
https://github.com/flutter/packages.git
synced 2025-06-30 23:03:11 +08:00
This reverts commit a2e65e9656a018692be2adc4f3e2d689b82adea5.
This commit is contained in:
@ -13,138 +13,25 @@ and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/developing-packages).
|
||||
-->
|
||||
|
||||
<!-- TODO(DavBot02): Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.-->
|
||||
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:
|
||||
|
||||
<!-- TODO(snat-s): Add stagger video demo -->
|
||||
|
||||
A wrap demo:
|
||||
|
||||
<!-- TODO(snat-s): Add wrap video 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(DavBot02): List prerequisites and provide or point to information on how to start using the package. -->
|
||||
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`.
|
||||
|
||||
<?code-excerpt "dynamic_grid_view_wrap.dart" (Example)?>
|
||||
```dart
|
||||
final List<Widget> 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`.
|
||||
|
||||
<?code-excerpt "dynamic_grid_view_builder.dart (Example)"?>
|
||||
```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.
|
||||
|
||||
<?code-excerpt "wrapping_fixed_axis.dart" (Example)?>
|
||||
```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(DavBot02): Add a code example of DynamicGrid.stagger -->
|
||||
|
||||
<!-- TODO(snat-s): Add a video of DynamicGrid.stagger -->
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
## Additional information
|
||||
|
||||
<!-- TODO(DavBot02): Tell users more about the package: where to find more information, how to
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more. -->
|
||||
from the package authors, and more.
|
||||
|
@ -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';
|
||||
|
@ -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.
|
||||
|
@ -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 <Widget>[],
|
||||
@ -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 <Widget>[],
|
||||
}) : super(
|
||||
gridDelegate: SliverGridDelegateWithWrapping(
|
||||
mainAxisSpacing: mainAxisSpacing,
|
||||
crossAxisSpacing: crossAxisSpacing,
|
||||
childCrossAxisExtent: childCrossAxisExtent,
|
||||
childMainAxisExtent: childMainAxisExtent,
|
||||
),
|
||||
);
|
||||
// TODO(snat-s): DynamicGridView.wrap?
|
||||
|
||||
// TODO(DavBot09): DynamicGridView.stagger?
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<FocusNode> focusNodes =
|
||||
List<FocusNode>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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<Widget> children = List<Widget>.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: <LocalizationsDelegate<dynamic>>[
|
||||
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<MaterialLocalizations> {
|
||||
@override
|
||||
bool isSupported(Locale locale) => true;
|
||||
|
||||
@override
|
||||
Future<MaterialLocalizations> load(Locale locale) =>
|
||||
DefaultMaterialLocalizations.load(locale);
|
||||
|
||||
@override
|
||||
bool shouldReload(MaterialLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
class WidgetsLocalizationsDelegate
|
||||
extends LocalizationsDelegate<WidgetsLocalizations> {
|
||||
@override
|
||||
bool isSupported(Locale locale) => true;
|
||||
|
||||
@override
|
||||
Future<WidgetsLocalizations> load(Locale locale) =>
|
||||
DefaultWidgetsLocalizations.load(locale);
|
||||
|
||||
@override
|
||||
bool shouldReload(WidgetsLocalizationsDelegate old) => false;
|
||||
}
|
Reference in New Issue
Block a user