Revert "Add SliverGrid and ScrollGrid" (#7769)
This commit is contained in:
parent
a0f0c42fe3
commit
32784d35f9
@ -131,9 +131,9 @@ class _GridPhotoViewerState extends State<GridPhotoViewer> with SingleTickerProv
|
|||||||
..translate(_offset.dx, _offset.dy)
|
..translate(_offset.dx, _offset.dy)
|
||||||
..scale(_scale),
|
..scale(_scale),
|
||||||
child: new ClipRect(
|
child: new ClipRect(
|
||||||
child: new Image.asset(config.photo.assetName, fit: ImageFit.cover),
|
child: new Image.asset(config.photo.assetName, fit: ImageFit.cover)
|
||||||
),
|
)
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -200,11 +200,11 @@ class GridDemoPhotoItem extends StatelessWidget {
|
|||||||
backgroundColor: Colors.black45,
|
backgroundColor: Colors.black45,
|
||||||
leading: new Icon(
|
leading: new Icon(
|
||||||
icon,
|
icon,
|
||||||
color: Colors.white,
|
color: Colors.white
|
||||||
),
|
)
|
||||||
),
|
)
|
||||||
),
|
),
|
||||||
child: image,
|
child: image
|
||||||
);
|
);
|
||||||
|
|
||||||
case GridDemoTileStyle.twoLine:
|
case GridDemoTileStyle.twoLine:
|
||||||
@ -217,11 +217,11 @@ class GridDemoPhotoItem extends StatelessWidget {
|
|||||||
subtitle: new _GridTitleText(photo.caption),
|
subtitle: new _GridTitleText(photo.caption),
|
||||||
trailing: new Icon(
|
trailing: new Icon(
|
||||||
icon,
|
icon,
|
||||||
color: Colors.white,
|
color: Colors.white
|
||||||
),
|
)
|
||||||
),
|
)
|
||||||
),
|
),
|
||||||
child: image,
|
child: image
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert(tileStyle != null);
|
assert(tileStyle != null);
|
||||||
@ -245,62 +245,62 @@ class GridListDemoState extends State<GridListDemo> {
|
|||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_0.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_0.jpg',
|
||||||
title: 'Philippines',
|
title: 'Philippines',
|
||||||
caption: 'Batad rice terraces',
|
caption: 'Batad rice terraces'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_1.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_1.jpg',
|
||||||
title: 'Italy',
|
title: 'Italy',
|
||||||
caption: 'Ceresole Reale',
|
caption: 'Ceresole Reale'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_2.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_2.jpg',
|
||||||
title: 'Somewhere',
|
title: 'Somewhere',
|
||||||
caption: 'Beautiful mountains',
|
caption: 'Beautiful mountains'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_3.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_3.jpg',
|
||||||
title: 'A place',
|
title: 'A place',
|
||||||
caption: 'Beautiful hills',
|
caption: 'Beautiful hills'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_4.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_4.jpg',
|
||||||
title: 'New Zealand',
|
title: 'New Zealand',
|
||||||
caption: 'View from the van',
|
caption: 'View from the van'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_5.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_5.jpg',
|
||||||
title: 'Autumn',
|
title: 'Autumn',
|
||||||
caption: 'The golden season',
|
caption: 'The golden season'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_6.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_6.jpg',
|
||||||
title: 'Germany',
|
title: 'Germany',
|
||||||
caption: 'Englischer Garten',
|
caption: 'Englischer Garten'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_7.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_7.jpg',
|
||||||
title: 'A country',
|
title: 'A country',
|
||||||
caption: 'Grass fields',
|
caption: 'Grass fields'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_8.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_8.jpg',
|
||||||
title: 'Mountain country',
|
title: 'Mountain country',
|
||||||
caption: 'River forest',
|
caption: 'River forest'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_9.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_9.jpg',
|
||||||
title: 'Alpine place',
|
title: 'Alpine place',
|
||||||
caption: 'Green hills',
|
caption: 'Green hills'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_10.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_10.jpg',
|
||||||
title: 'Desert land',
|
title: 'Desert land',
|
||||||
caption: 'Blue skies',
|
caption: 'Blue skies'
|
||||||
),
|
),
|
||||||
new Photo(
|
new Photo(
|
||||||
assetName: 'packages/flutter_gallery_assets/landscape_11.jpg',
|
assetName: 'packages/flutter_gallery_assets/landscape_11.jpg',
|
||||||
title: 'Narnia',
|
title: 'Narnia',
|
||||||
caption: 'Rocks and rivers',
|
caption: 'Rocks and rivers'
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -325,29 +325,31 @@ class GridListDemoState extends State<GridListDemo> {
|
|||||||
itemBuilder: (BuildContext context) => <PopupMenuItem<GridDemoTileStyle>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<GridDemoTileStyle>>[
|
||||||
new PopupMenuItem<GridDemoTileStyle>(
|
new PopupMenuItem<GridDemoTileStyle>(
|
||||||
value: GridDemoTileStyle.imageOnly,
|
value: GridDemoTileStyle.imageOnly,
|
||||||
child: new Text('Image only'),
|
child: new Text('Image only')
|
||||||
),
|
),
|
||||||
new PopupMenuItem<GridDemoTileStyle>(
|
new PopupMenuItem<GridDemoTileStyle>(
|
||||||
value: GridDemoTileStyle.oneLine,
|
value: GridDemoTileStyle.oneLine,
|
||||||
child: new Text('One line'),
|
child: new Text('One line')
|
||||||
),
|
),
|
||||||
new PopupMenuItem<GridDemoTileStyle>(
|
new PopupMenuItem<GridDemoTileStyle>(
|
||||||
value: GridDemoTileStyle.twoLine,
|
value: GridDemoTileStyle.twoLine,
|
||||||
child: new Text('Two line'),
|
child: new Text('Two line')
|
||||||
),
|
)
|
||||||
],
|
]
|
||||||
),
|
)
|
||||||
],
|
]
|
||||||
),
|
),
|
||||||
body: new Column(
|
body: new Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
new Expanded(
|
new Expanded(
|
||||||
child: new ScrollGrid.count(
|
child: new ScrollableGrid(
|
||||||
crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3,
|
delegate: new FixedColumnCountGridDelegate(
|
||||||
mainAxisSpacing: 4.0,
|
columnCount: (orientation == Orientation.portrait) ? 2 : 3,
|
||||||
crossAxisSpacing: 4.0,
|
rowSpacing: 4.0,
|
||||||
padding: const EdgeInsets.all(4.0),
|
columnSpacing: 4.0,
|
||||||
childAspectRatio: (orientation == Orientation.portrait) ? 1.0 : 1.3,
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
tileAspectRatio: (orientation == Orientation.portrait) ? 1.0 : 1.3
|
||||||
|
),
|
||||||
children: photos.map((Photo photo) {
|
children: photos.map((Photo photo) {
|
||||||
return new GridDemoPhotoItem(
|
return new GridDemoPhotoItem(
|
||||||
photo: photo,
|
photo: photo,
|
||||||
@ -358,7 +360,7 @@ class GridListDemoState extends State<GridListDemo> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}).toList(),
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -47,7 +47,6 @@ export 'src/rendering/shifted_box.dart';
|
|||||||
export 'src/rendering/sliver.dart';
|
export 'src/rendering/sliver.dart';
|
||||||
export 'src/rendering/sliver_app_bar.dart';
|
export 'src/rendering/sliver_app_bar.dart';
|
||||||
export 'src/rendering/sliver_block.dart';
|
export 'src/rendering/sliver_block.dart';
|
||||||
export 'src/rendering/sliver_grid.dart';
|
|
||||||
export 'src/rendering/sliver_list.dart';
|
export 'src/rendering/sliver_list.dart';
|
||||||
export 'src/rendering/sliver_multi_box_adaptor.dart';
|
export 'src/rendering/sliver_multi_box_adaptor.dart';
|
||||||
export 'src/rendering/sliver_padding.dart';
|
export 'src/rendering/sliver_padding.dart';
|
||||||
|
@ -282,9 +282,7 @@ class SliverConstraints extends Constraints {
|
|||||||
BoxConstraints asBoxConstraints({
|
BoxConstraints asBoxConstraints({
|
||||||
double minExtent: 0.0,
|
double minExtent: 0.0,
|
||||||
double maxExtent: double.INFINITY,
|
double maxExtent: double.INFINITY,
|
||||||
double crossAxisExtent,
|
|
||||||
}) {
|
}) {
|
||||||
crossAxisExtent ??= this.crossAxisExtent;
|
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case Axis.horizontal:
|
case Axis.horizontal:
|
||||||
return new BoxConstraints(
|
return new BoxConstraints(
|
||||||
@ -817,16 +815,13 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// the [RenderSliverHelpers] mixin and do not call this method yourself, you
|
/// the [RenderSliverHelpers] mixin and do not call this method yourself, you
|
||||||
/// do not need to implement this method.
|
/// do not need to implement this method.
|
||||||
@protected
|
@protected
|
||||||
double childMainAxisPosition(@checked RenderObject child) {
|
double childPosition(@checked RenderObject child) {
|
||||||
assert(() {
|
assert(() {
|
||||||
throw new FlutterError('$runtimeType does not implement childPosition.');
|
throw new FlutterError('$runtimeType does not implement childPosition.');
|
||||||
});
|
});
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
|
||||||
double childCrossAxisPosition(@checked RenderObject child) => 0.0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void applyPaintTransform(RenderObject child, Matrix4 transform) {
|
void applyPaintTransform(RenderObject child, Matrix4 transform) {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -1003,25 +998,24 @@ abstract class RenderSliverHelpers implements RenderSliver {
|
|||||||
/// This function takes care of converting the position from the sliver
|
/// This function takes care of converting the position from the sliver
|
||||||
/// coordinate system to the cartesian coordinate system used by [RenderBox].
|
/// coordinate system to the cartesian coordinate system used by [RenderBox].
|
||||||
///
|
///
|
||||||
/// This function relies on [childMainAxisPosition] to determine the position of
|
/// This function relies on [childPosition] to determine the position of
|
||||||
/// child in question.
|
/// child in question.
|
||||||
///
|
///
|
||||||
/// Calling this for a child that is not visible is not valid.
|
/// Calling this for a child that is not visible is not valid.
|
||||||
@protected
|
@protected
|
||||||
bool hitTestBoxChild(HitTestResult result, RenderBox child, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
bool hitTestBoxChild(HitTestResult result, RenderBox child, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
||||||
final bool rightWayUp = _getRightWayUp(constraints);
|
final bool rightWayUp = _getRightWayUp(constraints);
|
||||||
double absolutePosition = mainAxisPosition - childMainAxisPosition(child);
|
double absolutePosition = mainAxisPosition - childPosition(child);
|
||||||
final double absoluteCrossAxisPosition = crossAxisPosition - childCrossAxisPosition(child);
|
|
||||||
assert(constraints.axis != null);
|
assert(constraints.axis != null);
|
||||||
switch (constraints.axis) {
|
switch (constraints.axis) {
|
||||||
case Axis.horizontal:
|
case Axis.horizontal:
|
||||||
if (!rightWayUp)
|
if (!rightWayUp)
|
||||||
absolutePosition = child.size.width - absolutePosition;
|
absolutePosition = child.size.width - absolutePosition;
|
||||||
return child.hitTest(result, position: new Point(absolutePosition, absoluteCrossAxisPosition));
|
return child.hitTest(result, position: new Point(absolutePosition, crossAxisPosition));
|
||||||
case Axis.vertical:
|
case Axis.vertical:
|
||||||
if (!rightWayUp)
|
if (!rightWayUp)
|
||||||
absolutePosition = child.size.height - absolutePosition;
|
absolutePosition = child.size.height - absolutePosition;
|
||||||
return child.hitTest(result, position: new Point(absoluteCrossAxisPosition, absolutePosition));
|
return child.hitTest(result, position: new Point(crossAxisPosition, absolutePosition));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1029,27 +1023,25 @@ abstract class RenderSliverHelpers implements RenderSliver {
|
|||||||
/// Utility function for [applyPaintTransform] for use when the children are
|
/// Utility function for [applyPaintTransform] for use when the children are
|
||||||
/// [RenderBox] widgets.
|
/// [RenderBox] widgets.
|
||||||
///
|
///
|
||||||
/// This function turns the value returned by [childMainAxisPosition] and
|
/// This function turns the value returned by [childPosition] for the child in
|
||||||
/// [childCrossAxisPosition]for the child in question into a translation that
|
/// question into a translation that it then applies to the given matrix.
|
||||||
/// it then applies to the given matrix.
|
|
||||||
///
|
///
|
||||||
/// Calling this for a child that is not visible is not valid.
|
/// Calling this for a child that is not visible is not valid.
|
||||||
@protected
|
@protected
|
||||||
void applyPaintTransformForBoxChild(RenderBox child, Matrix4 transform) {
|
void applyPaintTransformForBoxChild(RenderBox child, Matrix4 transform) {
|
||||||
final bool rightWayUp = _getRightWayUp(constraints);
|
final bool rightWayUp = _getRightWayUp(constraints);
|
||||||
double delta = childMainAxisPosition(child);
|
double delta = childPosition(child);
|
||||||
final double crossAxisDelta = childCrossAxisPosition(child);
|
|
||||||
assert(constraints.axis != null);
|
assert(constraints.axis != null);
|
||||||
switch (constraints.axis) {
|
switch (constraints.axis) {
|
||||||
case Axis.horizontal:
|
case Axis.horizontal:
|
||||||
if (!rightWayUp)
|
if (!rightWayUp)
|
||||||
delta = geometry.paintExtent - child.size.width - delta;
|
delta = geometry.paintExtent - child.size.width - delta;
|
||||||
transform.translate(delta, crossAxisDelta);
|
transform.translate(delta, 0.0);
|
||||||
break;
|
break;
|
||||||
case Axis.vertical:
|
case Axis.vertical:
|
||||||
if (!rightWayUp)
|
if (!rightWayUp)
|
||||||
delta = geometry.paintExtent - child.size.height - delta;
|
delta = geometry.paintExtent - child.size.height - delta;
|
||||||
transform.translate(crossAxisDelta, delta);
|
transform.translate(0.0, delta);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1846,7 +1838,7 @@ class RenderSliverToBoxAdapter extends RenderSliver with RenderObjectWithChildMi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderBox child) {
|
double childPosition(RenderBox child) {
|
||||||
return -constraints.scrollOffset;
|
return -constraints.scrollOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ abstract class RenderSliverAppBar extends RenderSliver with RenderObjectWithChil
|
|||||||
///
|
///
|
||||||
/// If there is no child, this should return 0.0.
|
/// If there is no child, this should return 0.0.
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(@checked RenderObject child) => super.childMainAxisPosition(child);
|
double childPosition(@checked RenderObject child) => super.childPosition(child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hitTestChildren(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
bool hitTestChildren(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
||||||
@ -155,16 +155,16 @@ abstract class RenderSliverAppBar extends RenderSliver with RenderObjectWithChil
|
|||||||
assert(constraints.axisDirection != null);
|
assert(constraints.axisDirection != null);
|
||||||
switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
|
switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
|
||||||
case AxisDirection.up:
|
case AxisDirection.up:
|
||||||
offset += new Offset(0.0, geometry.paintExtent - childMainAxisPosition(child) - childExtent);
|
offset += new Offset(0.0, geometry.paintExtent - childPosition(child) - childExtent);
|
||||||
break;
|
break;
|
||||||
case AxisDirection.down:
|
case AxisDirection.down:
|
||||||
offset += new Offset(0.0, childMainAxisPosition(child));
|
offset += new Offset(0.0, childPosition(child));
|
||||||
break;
|
break;
|
||||||
case AxisDirection.left:
|
case AxisDirection.left:
|
||||||
offset += new Offset(geometry.paintExtent - childMainAxisPosition(child) - childExtent, 0.0);
|
offset += new Offset(geometry.paintExtent - childPosition(child) - childExtent, 0.0);
|
||||||
break;
|
break;
|
||||||
case AxisDirection.right:
|
case AxisDirection.right:
|
||||||
offset += new Offset(childMainAxisPosition(child), 0.0);
|
offset += new Offset(childPosition(child), 0.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context.paintChild(child, offset);
|
context.paintChild(child, offset);
|
||||||
@ -180,7 +180,7 @@ abstract class RenderSliverAppBar extends RenderSliver with RenderObjectWithChil
|
|||||||
description.add('maxExtent: EXCEPTION (${e.runtimeType}) WHILE COMPUTING MAX EXTENT');
|
description.add('maxExtent: EXCEPTION (${e.runtimeType}) WHILE COMPUTING MAX EXTENT');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
description.add('child position: ${childMainAxisPosition(child).toStringAsFixed(1)}');
|
description.add('child position: ${childPosition(child).toStringAsFixed(1)}');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
description.add('child position: EXCEPTION (${e.runtimeType}) WHILE COMPUTING CHILD POSITION');
|
description.add('child position: EXCEPTION (${e.runtimeType}) WHILE COMPUTING CHILD POSITION');
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ abstract class RenderSliverScrollingAppBar extends RenderSliverAppBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderBox child) {
|
double childPosition(RenderBox child) {
|
||||||
assert(child == this.child);
|
assert(child == this.child);
|
||||||
return _childPosition;
|
return _childPosition;
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ abstract class RenderSliverPinnedAppBar extends RenderSliverAppBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderBox child) {
|
double childPosition(RenderBox child) {
|
||||||
assert(child == this.child);
|
assert(child == this.child);
|
||||||
return constraints?.overlap;
|
return constraints?.overlap;
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ abstract class RenderSliverFloatingAppBar extends RenderSliverAppBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderBox child) {
|
double childPosition(RenderBox child) {
|
||||||
assert(child == this.child);
|
assert(child == this.child);
|
||||||
return _childPosition;
|
return _childPosition;
|
||||||
}
|
}
|
||||||
|
@ -184,18 +184,17 @@ class RenderSliverBlock extends RenderSliverMultiBoxAdaptor {
|
|||||||
collectGarbage(leadingGarbage, trailingGarbage);
|
collectGarbage(leadingGarbage, trailingGarbage);
|
||||||
|
|
||||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
||||||
double estimatedMaxScrollOffset;
|
double estimatedTotalExtent;
|
||||||
if (reachedEnd) {
|
if (reachedEnd) {
|
||||||
estimatedMaxScrollOffset = endScrollOffset;
|
estimatedTotalExtent = endScrollOffset;
|
||||||
} else {
|
} else {
|
||||||
estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
estimatedTotalExtent = childManager.estimateScrollOffsetExtent(
|
||||||
constraints,
|
|
||||||
firstIndex: indexOf(firstChild),
|
firstIndex: indexOf(firstChild),
|
||||||
lastIndex: indexOf(lastChild),
|
lastIndex: indexOf(lastChild),
|
||||||
leadingScrollOffset: offsetOf(firstChild),
|
leadingScrollOffset: offsetOf(firstChild),
|
||||||
trailingScrollOffset: endScrollOffset,
|
trailingScrollOffset: endScrollOffset,
|
||||||
);
|
);
|
||||||
assert(estimatedMaxScrollOffset >= endScrollOffset - offsetOf(firstChild));
|
assert(estimatedTotalExtent >= endScrollOffset - offsetOf(firstChild));
|
||||||
}
|
}
|
||||||
final double paintedExtent = calculatePaintOffset(
|
final double paintedExtent = calculatePaintOffset(
|
||||||
constraints,
|
constraints,
|
||||||
@ -203,9 +202,9 @@ class RenderSliverBlock extends RenderSliverMultiBoxAdaptor {
|
|||||||
to: endScrollOffset,
|
to: endScrollOffset,
|
||||||
);
|
);
|
||||||
geometry = new SliverGeometry(
|
geometry = new SliverGeometry(
|
||||||
scrollExtent: estimatedMaxScrollOffset,
|
scrollExtent: estimatedTotalExtent,
|
||||||
paintExtent: paintedExtent,
|
paintExtent: paintedExtent,
|
||||||
maxPaintExtent: estimatedMaxScrollOffset,
|
maxPaintExtent: estimatedTotalExtent,
|
||||||
// Conservative to avoid flickering away the clip during scroll.
|
// Conservative to avoid flickering away the clip during scroll.
|
||||||
hasVisualOverflow: endScrollOffset > targetEndScrollOffset || constraints.scrollOffset > 0.0,
|
hasVisualOverflow: endScrollOffset > targetEndScrollOffset || constraints.scrollOffset > 0.0,
|
||||||
);
|
);
|
||||||
|
@ -1,426 +0,0 @@
|
|||||||
// Copyright 2017 The Chromium 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 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
import 'box.dart';
|
|
||||||
import 'object.dart';
|
|
||||||
import 'sliver.dart';
|
|
||||||
import 'sliver_multi_box_adaptor.dart';
|
|
||||||
|
|
||||||
/// Describes the placement of a child in a [RenderSliverGrid].
|
|
||||||
///
|
|
||||||
/// See also:
|
|
||||||
///
|
|
||||||
/// * [SliverGridDelegate.getGeometryForChildIndex], which returns this object
|
|
||||||
/// to describe the child's placement.
|
|
||||||
/// * [RenderSliverGrid], which uses this class during its
|
|
||||||
/// [RenderSliverGrid.performLayout] method.
|
|
||||||
class SliverGridGeometry {
|
|
||||||
/// Creates an object that describes the placement of a child in a [RenderSliverGrid].
|
|
||||||
const SliverGridGeometry({
|
|
||||||
this.scrollOffset,
|
|
||||||
this.crossAxisOffset,
|
|
||||||
this.mainAxisExtent,
|
|
||||||
this.crossAxisExtent,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The scroll offset of the leading edge of the child relative to the leading
|
|
||||||
/// edge of the parent.
|
|
||||||
final double scrollOffset;
|
|
||||||
|
|
||||||
/// The offset of the child in the non-scrolling axis.
|
|
||||||
///
|
|
||||||
/// If the scroll axis is vertical, this offset is from the left-most edge of
|
|
||||||
/// the parent to the left-most edge of the child. If the scroll axis is
|
|
||||||
/// horizontal, this offset is from the top-most edge of the parent to the
|
|
||||||
/// top-most edge of the child.
|
|
||||||
final double crossAxisOffset;
|
|
||||||
|
|
||||||
/// The extent of the child in the scrolling axis.
|
|
||||||
///
|
|
||||||
/// If the scroll axis is vertical, this extent is the child's height. If the
|
|
||||||
/// scroll axis is horizontal, this extent is the child's width.
|
|
||||||
final double mainAxisExtent;
|
|
||||||
|
|
||||||
/// The extent of the child in the non-scrolling axis.
|
|
||||||
///
|
|
||||||
/// If the scroll axis is vertical, this extent is the child's width. If the
|
|
||||||
/// scroll axis is horizontal, this extent is the child's height.
|
|
||||||
final double crossAxisExtent;
|
|
||||||
|
|
||||||
/// Returns a tight [BoxConstraints] that forces the child to have the
|
|
||||||
/// required size.
|
|
||||||
BoxConstraints getBoxConstraints(SliverConstraints constraints) {
|
|
||||||
return constraints.asBoxConstraints(
|
|
||||||
minExtent: mainAxisExtent,
|
|
||||||
maxExtent: mainAxisExtent,
|
|
||||||
crossAxisExtent: crossAxisExtent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SliverGridParentData extends SliverMultiBoxAdaptorParentData {
|
|
||||||
double crossAxisOffset;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => 'crossAxisOffset=$crossAxisOffset; ${super.toString()}';
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class SliverGridDelegate {
|
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
|
||||||
/// const constructors so that they can be used in const expressions.
|
|
||||||
const SliverGridDelegate();
|
|
||||||
|
|
||||||
int getMinChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset);
|
|
||||||
|
|
||||||
int getMaxChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset);
|
|
||||||
|
|
||||||
SliverGridGeometry getGeometryForChildIndex(SliverConstraints constraints, int index);
|
|
||||||
|
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, int childCount);
|
|
||||||
|
|
||||||
bool shouldRelayout(@checked SliverGridDelegate oldDelegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SliverGridDelegateWithFixedCrossAxisCount extends SliverGridDelegate {
|
|
||||||
const SliverGridDelegateWithFixedCrossAxisCount({
|
|
||||||
@required this.crossAxisCount,
|
|
||||||
this.mainAxisSpacing: 0.0,
|
|
||||||
this.crossAxisSpacing: 0.0,
|
|
||||||
this.childAspectRatio: 1.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The number of children in the cross axis.
|
|
||||||
final int crossAxisCount;
|
|
||||||
|
|
||||||
/// 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 ratio of the cross-axis to the main-axis extent of each child.
|
|
||||||
final double childAspectRatio;
|
|
||||||
|
|
||||||
bool _debugAssertIsValid() {
|
|
||||||
assert(crossAxisCount > 0);
|
|
||||||
assert(mainAxisSpacing >= 0.0);
|
|
||||||
assert(crossAxisSpacing >= 0.0);
|
|
||||||
assert(childAspectRatio > 0.0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
double _getMainAxisStride(double crossAxisExtent) {
|
|
||||||
final double usableCrossAxisExtent = crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
|
||||||
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
|
||||||
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
|
||||||
return childMainAxisExtent + mainAxisSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getMinChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset) {
|
|
||||||
assert(_debugAssertIsValid());
|
|
||||||
return crossAxisCount * (scrollOffset ~/ _getMainAxisStride(constraints.crossAxisExtent));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getMaxChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset) {
|
|
||||||
assert(_debugAssertIsValid());
|
|
||||||
final int mainAxisCount = (scrollOffset / _getMainAxisStride(constraints.crossAxisExtent)).ceil();
|
|
||||||
return math.max(0, crossAxisCount * mainAxisCount - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
SliverGridGeometry getGeometryForChildIndex(SliverConstraints constraints, int index) {
|
|
||||||
final double usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
|
||||||
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
|
||||||
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
|
||||||
final double mainAxisStride = childMainAxisExtent + mainAxisSpacing;
|
|
||||||
final double crossAxisStrid = childCrossAxisExtent + crossAxisSpacing;
|
|
||||||
assert(mainAxisStride == _getMainAxisStride(constraints.crossAxisExtent));
|
|
||||||
|
|
||||||
return new SliverGridGeometry(
|
|
||||||
scrollOffset: (index ~/ crossAxisCount) * mainAxisStride,
|
|
||||||
crossAxisOffset: (index % crossAxisCount) * crossAxisStrid,
|
|
||||||
mainAxisExtent: childMainAxisExtent,
|
|
||||||
crossAxisExtent: childCrossAxisExtent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, int childCount) {
|
|
||||||
if (childCount == null)
|
|
||||||
return null;
|
|
||||||
final int mainAxisCount = ((childCount - 1) / crossAxisCount).floor() + 1;
|
|
||||||
return _getMainAxisStride(constraints.crossAxisExtent) * mainAxisCount - mainAxisSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRelayout(SliverGridDelegateWithFixedCrossAxisCount oldDelegate) {
|
|
||||||
return oldDelegate.crossAxisCount != crossAxisCount
|
|
||||||
|| oldDelegate.mainAxisSpacing != mainAxisSpacing
|
|
||||||
|| oldDelegate.crossAxisSpacing != crossAxisSpacing
|
|
||||||
|| oldDelegate.childAspectRatio != childAspectRatio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [GridDelegate] that fills the width with a variable number of tiles.
|
|
||||||
///
|
|
||||||
/// This delegate will select a tile width that is as large as possible subject
|
|
||||||
/// to the following conditions:
|
|
||||||
///
|
|
||||||
/// - The tile width evenly divides the width of the grid.
|
|
||||||
/// - The tile width is at most [maxTileWidth].
|
|
||||||
class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate {
|
|
||||||
/// Creates a grid delegate that uses a max tile width.
|
|
||||||
///
|
|
||||||
/// The [maxTileWidth] argument must not be null.
|
|
||||||
const SliverGridDelegateWithMaxCrossAxisExtent({
|
|
||||||
@required this.maxCrossAxisExtent,
|
|
||||||
this.mainAxisSpacing: 0.0,
|
|
||||||
this.crossAxisSpacing: 0.0,
|
|
||||||
this.childAspectRatio: 1.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The number of children in the cross axis.
|
|
||||||
final double maxCrossAxisExtent;
|
|
||||||
|
|
||||||
/// 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 ratio of the cross-axis to the main-axis extent of each child.
|
|
||||||
final double childAspectRatio;
|
|
||||||
|
|
||||||
bool _debugAssertIsValid() {
|
|
||||||
assert(maxCrossAxisExtent > 0.0);
|
|
||||||
assert(mainAxisSpacing >= 0.0);
|
|
||||||
assert(crossAxisSpacing >= 0.0);
|
|
||||||
assert(childAspectRatio > 0.0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getCrossAxisCount(double crossAxisExtent) {
|
|
||||||
return (crossAxisExtent / (maxCrossAxisExtent + crossAxisSpacing)).ceil();
|
|
||||||
}
|
|
||||||
|
|
||||||
double _getMainAxisStride(double crossAxisExtent, int crossAxisCount) {
|
|
||||||
final double usableCrossAxisExtent = crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
|
||||||
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
|
||||||
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
|
||||||
return childMainAxisExtent + mainAxisSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getMinChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset) {
|
|
||||||
assert(_debugAssertIsValid());
|
|
||||||
final double crossAxisExtent = constraints.crossAxisExtent;
|
|
||||||
final int crossAxisCount = _getCrossAxisCount(crossAxisExtent);
|
|
||||||
return crossAxisCount * (scrollOffset ~/ _getMainAxisStride(crossAxisExtent, crossAxisCount));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int getMaxChildIndexForScrollOffset(SliverConstraints constraints, double scrollOffset) {
|
|
||||||
assert(_debugAssertIsValid());
|
|
||||||
final double crossAxisExtent = constraints.crossAxisExtent;
|
|
||||||
final int crossAxisCount = _getCrossAxisCount(crossAxisExtent);
|
|
||||||
final int mainAxisCount = (scrollOffset / _getMainAxisStride(crossAxisExtent, crossAxisCount)).ceil();
|
|
||||||
return math.max(0, crossAxisCount * mainAxisCount - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
SliverGridGeometry getGeometryForChildIndex(SliverConstraints constraints, int index) {
|
|
||||||
final int crossAxisCount = _getCrossAxisCount(constraints.crossAxisExtent);
|
|
||||||
final double usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
|
||||||
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
|
||||||
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
|
||||||
final double mainAxisStride = childMainAxisExtent + mainAxisSpacing;
|
|
||||||
final double crossAxisStrid = childCrossAxisExtent + crossAxisSpacing;
|
|
||||||
assert(mainAxisStride == _getMainAxisStride(constraints.crossAxisExtent, crossAxisCount));
|
|
||||||
|
|
||||||
return new SliverGridGeometry(
|
|
||||||
scrollOffset: (index ~/ crossAxisCount) * mainAxisStride,
|
|
||||||
crossAxisOffset: (index % crossAxisCount) * crossAxisStrid,
|
|
||||||
mainAxisExtent: childMainAxisExtent,
|
|
||||||
crossAxisExtent: childCrossAxisExtent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, int childCount) {
|
|
||||||
if (childCount == null)
|
|
||||||
return null;
|
|
||||||
final double crossAxisExtent = constraints.crossAxisExtent;
|
|
||||||
final int crossAxisCount = _getCrossAxisCount(crossAxisExtent);
|
|
||||||
final int mainAxisCount = ((childCount - 1) / crossAxisCount).floor() + 1;
|
|
||||||
return _getMainAxisStride(crossAxisExtent, crossAxisCount) * mainAxisCount - mainAxisSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRelayout(SliverGridDelegateWithMaxCrossAxisExtent oldDelegate) {
|
|
||||||
return oldDelegate.maxCrossAxisExtent != maxCrossAxisExtent
|
|
||||||
|| oldDelegate.mainAxisSpacing != mainAxisSpacing
|
|
||||||
|| oldDelegate.crossAxisSpacing != crossAxisSpacing
|
|
||||||
|| oldDelegate.childAspectRatio != childAspectRatio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
|
|
||||||
RenderSliverGrid({
|
|
||||||
@required RenderSliverBoxChildManager childManager,
|
|
||||||
@required SliverGridDelegate gridDelegate,
|
|
||||||
}) : _gridDelegate = gridDelegate,
|
|
||||||
super(childManager: childManager) {
|
|
||||||
gridDelegate != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setupParentData(RenderObject child) {
|
|
||||||
if (child.parentData is! SliverGridParentData)
|
|
||||||
child.parentData = new SliverGridParentData();
|
|
||||||
}
|
|
||||||
|
|
||||||
SliverGridDelegate get gridDelegate => _gridDelegate;
|
|
||||||
SliverGridDelegate _gridDelegate;
|
|
||||||
|
|
||||||
set gridDelegate(SliverGridDelegate newDelegate) {
|
|
||||||
assert(newDelegate != null);
|
|
||||||
if (_gridDelegate == newDelegate)
|
|
||||||
return;
|
|
||||||
if (newDelegate.runtimeType != _gridDelegate.runtimeType ||
|
|
||||||
newDelegate.shouldRelayout(_gridDelegate))
|
|
||||||
markNeedsLayout();
|
|
||||||
_gridDelegate = newDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
double childCrossAxisPosition(RenderBox child) {
|
|
||||||
final SliverGridParentData childParentData = child.parentData;
|
|
||||||
return childParentData.crossAxisOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void performLayout() {
|
|
||||||
assert(childManager.debugAssertChildListLocked());
|
|
||||||
final double scrollOffset = constraints.scrollOffset;
|
|
||||||
assert(scrollOffset >= 0.0);
|
|
||||||
final double remainingPaintExtent = constraints.remainingPaintExtent;
|
|
||||||
assert(remainingPaintExtent >= 0.0);
|
|
||||||
final double targetEndScrollOffset = scrollOffset + remainingPaintExtent;
|
|
||||||
|
|
||||||
final int firstIndex = _gridDelegate.getMinChildIndexForScrollOffset(constraints, scrollOffset);
|
|
||||||
final int targetLastIndex = _gridDelegate.getMaxChildIndexForScrollOffset(constraints, targetEndScrollOffset);
|
|
||||||
|
|
||||||
if (firstChild != null) {
|
|
||||||
final int oldFirstIndex = indexOf(firstChild);
|
|
||||||
final int oldLastIndex = indexOf(lastChild);
|
|
||||||
final int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, childCount);
|
|
||||||
final int trailingGarbage = (oldLastIndex - targetLastIndex).clamp(0, childCount);
|
|
||||||
if (leadingGarbage + trailingGarbage > 0)
|
|
||||||
collectGarbage(leadingGarbage, trailingGarbage);
|
|
||||||
}
|
|
||||||
|
|
||||||
final SliverGridGeometry firstChildGridGeometry = _gridDelegate
|
|
||||||
.getGeometryForChildIndex(constraints, firstIndex);
|
|
||||||
double leadingScrollOffset = firstChildGridGeometry.scrollOffset;
|
|
||||||
double trailingScrollOffset = firstChildGridGeometry.scrollOffset;
|
|
||||||
|
|
||||||
if (firstChild == null) {
|
|
||||||
if (!addInitialChild(index: firstIndex,
|
|
||||||
scrollOffset: firstChildGridGeometry.scrollOffset)) {
|
|
||||||
// There are no children.
|
|
||||||
geometry = SliverGeometry.zero;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderBox trailingChildWithLayout;
|
|
||||||
|
|
||||||
for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) {
|
|
||||||
final SliverGridGeometry gridGeometry = _gridDelegate
|
|
||||||
.getGeometryForChildIndex(constraints, index);
|
|
||||||
final RenderBox child = insertAndLayoutLeadingChild(
|
|
||||||
gridGeometry.getBoxConstraints(constraints));
|
|
||||||
final SliverGridParentData childParentData = child.parentData;
|
|
||||||
childParentData.scrollOffset = gridGeometry.scrollOffset;
|
|
||||||
childParentData.crossAxisOffset = gridGeometry.crossAxisOffset;
|
|
||||||
assert(childParentData.index == index);
|
|
||||||
trailingChildWithLayout ??= child;
|
|
||||||
if (gridGeometry.scrollOffset > trailingScrollOffset)
|
|
||||||
trailingScrollOffset = gridGeometry.scrollOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(offsetOf(firstChild) <= scrollOffset);
|
|
||||||
|
|
||||||
if (trailingChildWithLayout == null) {
|
|
||||||
firstChild.layout(firstChildGridGeometry.getBoxConstraints(constraints));
|
|
||||||
final SliverGridParentData childParentData = firstChild.parentData;
|
|
||||||
childParentData.crossAxisOffset = firstChildGridGeometry.crossAxisOffset;
|
|
||||||
assert(childParentData.scrollOffset ==
|
|
||||||
firstChildGridGeometry.scrollOffset);
|
|
||||||
trailingChildWithLayout = firstChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = indexOf(trailingChildWithLayout) + 1; index <=
|
|
||||||
targetLastIndex; ++index) {
|
|
||||||
final SliverGridGeometry gridGeometry = _gridDelegate
|
|
||||||
.getGeometryForChildIndex(constraints, index);
|
|
||||||
final BoxConstraints childConstraints = gridGeometry.getBoxConstraints(
|
|
||||||
constraints);
|
|
||||||
RenderBox child = childAfter(trailingChildWithLayout);
|
|
||||||
if (child == null) {
|
|
||||||
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
|
|
||||||
if (child == null) {
|
|
||||||
// We have run out of children.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
child.layout(childConstraints);
|
|
||||||
}
|
|
||||||
trailingChildWithLayout = child;
|
|
||||||
assert(child != null);
|
|
||||||
final SliverGridParentData childParentData = child.parentData;
|
|
||||||
childParentData.scrollOffset = gridGeometry.scrollOffset;
|
|
||||||
childParentData.crossAxisOffset = gridGeometry.crossAxisOffset;
|
|
||||||
assert(childParentData.index == index);
|
|
||||||
if (gridGeometry.scrollOffset > trailingScrollOffset)
|
|
||||||
trailingScrollOffset = gridGeometry.scrollOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int lastIndex = indexOf(lastChild);
|
|
||||||
|
|
||||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
|
||||||
assert(indexOf(firstChild) == firstIndex);
|
|
||||||
assert(lastIndex <= targetLastIndex);
|
|
||||||
|
|
||||||
final double estimatedTotalExtent = childManager.estimateMaxScrollOffset(
|
|
||||||
constraints,
|
|
||||||
firstIndex: firstIndex,
|
|
||||||
lastIndex: lastIndex,
|
|
||||||
leadingScrollOffset: leadingScrollOffset,
|
|
||||||
trailingScrollOffset: trailingScrollOffset,
|
|
||||||
);
|
|
||||||
|
|
||||||
final double paintedExtent = calculatePaintOffset(
|
|
||||||
constraints,
|
|
||||||
from: leadingScrollOffset,
|
|
||||||
to: trailingScrollOffset,
|
|
||||||
);
|
|
||||||
|
|
||||||
geometry = new SliverGeometry(
|
|
||||||
scrollExtent: estimatedTotalExtent,
|
|
||||||
paintExtent: paintedExtent,
|
|
||||||
maxPaintExtent: estimatedTotalExtent,
|
|
||||||
// Conservative to avoid complexity.
|
|
||||||
hasVisualOverflow: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert(childManager.debugAssertChildListLocked());
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,9 +14,7 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
|
|||||||
RenderSliverList({
|
RenderSliverList({
|
||||||
@required RenderSliverBoxChildManager childManager,
|
@required RenderSliverBoxChildManager childManager,
|
||||||
double itemExtent,
|
double itemExtent,
|
||||||
}) : _itemExtent = itemExtent, super(childManager: childManager) {
|
}) : _itemExtent = itemExtent, super(childManager: childManager);
|
||||||
assert(itemExtent != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The main-axis extent of each item in the list.
|
/// The main-axis extent of each item in the list.
|
||||||
double get itemExtent => _itemExtent;
|
double get itemExtent => _itemExtent;
|
||||||
@ -107,8 +105,7 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
|
|||||||
assert(indexOf(firstChild) == firstIndex);
|
assert(indexOf(firstChild) == firstIndex);
|
||||||
assert(lastIndex <= targetLastIndex);
|
assert(lastIndex <= targetLastIndex);
|
||||||
|
|
||||||
final double estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
final double estimatedTotalExtent = childManager.estimateScrollOffsetExtent(
|
||||||
constraints,
|
|
||||||
firstIndex: firstIndex,
|
firstIndex: firstIndex,
|
||||||
lastIndex: lastIndex,
|
lastIndex: lastIndex,
|
||||||
leadingScrollOffset: leadingScrollOffset,
|
leadingScrollOffset: leadingScrollOffset,
|
||||||
@ -122,9 +119,9 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
geometry = new SliverGeometry(
|
geometry = new SliverGeometry(
|
||||||
scrollExtent: estimatedMaxScrollOffset,
|
scrollExtent: estimatedTotalExtent,
|
||||||
paintExtent: paintedExtent,
|
paintExtent: paintedExtent,
|
||||||
maxPaintExtent: estimatedMaxScrollOffset,
|
maxPaintExtent: estimatedTotalExtent,
|
||||||
// Conservative to avoid flickering away the clip during scroll.
|
// Conservative to avoid flickering away the clip during scroll.
|
||||||
hasVisualOverflow: lastIndex >= targetLastIndex || constraints.scrollOffset > 0.0,
|
hasVisualOverflow: lastIndex >= targetLastIndex || constraints.scrollOffset > 0.0,
|
||||||
);
|
);
|
||||||
|
@ -61,7 +61,7 @@ abstract class RenderSliverBoxChildManager {
|
|||||||
/// Must return the total distance from the start of the child with the
|
/// Must return the total distance from the start of the child with the
|
||||||
/// earliest possible index to the end of the child with the last possible
|
/// earliest possible index to the end of the child with the last possible
|
||||||
/// index.
|
/// index.
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, {
|
double estimateScrollOffsetExtent({
|
||||||
int firstIndex,
|
int firstIndex,
|
||||||
int lastIndex,
|
int lastIndex,
|
||||||
double leadingScrollOffset,
|
double leadingScrollOffset,
|
||||||
@ -304,7 +304,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderBox child) {
|
double childPosition(RenderBox child) {
|
||||||
return offsetOf(child) - constraints.scrollOffset;
|
return offsetOf(child) - constraints.scrollOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,46 +319,37 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
|
|||||||
return;
|
return;
|
||||||
// offset is to the top-left corner, regardless of our axis direction.
|
// offset is to the top-left corner, regardless of our axis direction.
|
||||||
// originOffset gives us the delta from the real origin to the origin in the axis direction.
|
// originOffset gives us the delta from the real origin to the origin in the axis direction.
|
||||||
Offset mainAxisUnit, crossAxisUnit, originOffset;
|
Offset unitOffset, originOffset;
|
||||||
bool addExtent;
|
bool addExtent;
|
||||||
switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
|
switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
|
||||||
case AxisDirection.up:
|
case AxisDirection.up:
|
||||||
mainAxisUnit = const Offset(0.0, -1.0);
|
unitOffset = const Offset(0.0, -1.0);
|
||||||
crossAxisUnit = const Offset(1.0, 0.0);
|
|
||||||
originOffset = offset + new Offset(0.0, geometry.paintExtent);
|
originOffset = offset + new Offset(0.0, geometry.paintExtent);
|
||||||
addExtent = true;
|
addExtent = true;
|
||||||
break;
|
break;
|
||||||
case AxisDirection.right:
|
case AxisDirection.right:
|
||||||
mainAxisUnit = const Offset(1.0, 0.0);
|
unitOffset = const Offset(1.0, 0.0);
|
||||||
crossAxisUnit = const Offset(0.0, 1.0);
|
|
||||||
originOffset = offset;
|
originOffset = offset;
|
||||||
addExtent = false;
|
addExtent = false;
|
||||||
break;
|
break;
|
||||||
case AxisDirection.down:
|
case AxisDirection.down:
|
||||||
mainAxisUnit = const Offset(0.0, 1.0);
|
unitOffset = const Offset(0.0, 1.0);
|
||||||
crossAxisUnit = const Offset(1.0, 0.0);
|
|
||||||
originOffset = offset;
|
originOffset = offset;
|
||||||
addExtent = false;
|
addExtent = false;
|
||||||
break;
|
break;
|
||||||
case AxisDirection.left:
|
case AxisDirection.left:
|
||||||
mainAxisUnit = const Offset(-1.0, 0.0);
|
unitOffset = const Offset(-1.0, 0.0);
|
||||||
crossAxisUnit = const Offset(0.0, 1.0);
|
|
||||||
originOffset = offset + new Offset(geometry.paintExtent, 0.0);
|
originOffset = offset + new Offset(geometry.paintExtent, 0.0);
|
||||||
addExtent = true;
|
addExtent = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(mainAxisUnit != null);
|
assert(unitOffset != null);
|
||||||
assert(addExtent != null);
|
assert(addExtent != null);
|
||||||
RenderBox child = firstChild;
|
RenderBox child = firstChild;
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
final double mainAxisDelta = childMainAxisPosition(child);
|
Offset childOffset = originOffset + unitOffset * childPosition(child);
|
||||||
final double crossAxisDelta = childCrossAxisPosition(child);
|
|
||||||
Offset childOffset = new Offset(
|
|
||||||
originOffset.dx + mainAxisUnit.dx * mainAxisDelta + crossAxisUnit.dx * crossAxisDelta,
|
|
||||||
originOffset.dy + mainAxisUnit.dy * mainAxisDelta + crossAxisUnit.dy * crossAxisDelta,
|
|
||||||
);
|
|
||||||
if (addExtent)
|
if (addExtent)
|
||||||
childOffset += mainAxisUnit * paintExtentOf(child);
|
childOffset += unitOffset * paintExtentOf(child);
|
||||||
context.paintChild(child, childOffset);
|
context.paintChild(child, childOffset);
|
||||||
child = childAfter(child);
|
child = childAfter(child);
|
||||||
}
|
}
|
||||||
|
@ -262,24 +262,17 @@ class RenderSliverPadding extends RenderSliver with RenderObjectWithChildMixin<R
|
|||||||
@override
|
@override
|
||||||
bool hitTestChildren(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
bool hitTestChildren(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
||||||
if (child.geometry.hitTestExtent > 0.0)
|
if (child.geometry.hitTestExtent > 0.0)
|
||||||
return child.hitTest(result, mainAxisPosition: mainAxisPosition - childMainAxisPosition(child), crossAxisPosition: crossAxisPosition - childCrossAxisPosition(child));
|
return child.hitTest(result, mainAxisPosition: mainAxisPosition - childPosition(child), crossAxisPosition: crossAxisPosition - startPadding);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double childMainAxisPosition(RenderSliver child) {
|
double childPosition(RenderSliver child) {
|
||||||
assert(child != null);
|
assert(child != null);
|
||||||
assert(child == this.child);
|
assert(child == this.child);
|
||||||
return calculatePaintOffset(constraints, from: 0.0, to: beforePadding);
|
return calculatePaintOffset(constraints, from: 0.0, to: beforePadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
double childCrossAxisPosition(RenderSliver child) {
|
|
||||||
assert(child != null);
|
|
||||||
assert(child == this.child);
|
|
||||||
return startPadding;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void applyPaintTransform(RenderObject child, Matrix4 transform) {
|
void applyPaintTransform(RenderObject child, Matrix4 transform) {
|
||||||
assert(child != null);
|
assert(child != null);
|
||||||
|
@ -3,31 +3,21 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
import 'framework.dart';
|
import 'framework.dart';
|
||||||
import 'basic.dart';
|
import 'basic.dart';
|
||||||
import 'scrollable.dart';
|
import 'scrollable.dart';
|
||||||
import 'sliver.dart';
|
import 'sliver.dart';
|
||||||
|
|
||||||
AxisDirection _getDirection(BuildContext context, Axis scrollDirection) {
|
|
||||||
// TODO(abarth): Consider reading direction.
|
|
||||||
switch (scrollDirection) {
|
|
||||||
case Axis.horizontal:
|
|
||||||
return AxisDirection.right;
|
|
||||||
case Axis.vertical:
|
|
||||||
return AxisDirection.down;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScrollView extends StatelessWidget {
|
class ScrollView extends StatelessWidget {
|
||||||
ScrollView({
|
ScrollView({
|
||||||
Key key,
|
Key key,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.scrollDirection: Axis.vertical,
|
this.scrollDirection: Axis.vertical,
|
||||||
|
this.anchor: 0.0,
|
||||||
this.initialScrollOffset: 0.0,
|
this.initialScrollOffset: 0.0,
|
||||||
this.itemExtent,
|
this.itemExtent,
|
||||||
|
this.center,
|
||||||
this.children,
|
this.children,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -35,109 +25,50 @@ class ScrollView extends StatelessWidget {
|
|||||||
|
|
||||||
final Axis scrollDirection;
|
final Axis scrollDirection;
|
||||||
|
|
||||||
|
final double anchor;
|
||||||
|
|
||||||
final double initialScrollOffset;
|
final double initialScrollOffset;
|
||||||
|
|
||||||
final double itemExtent;
|
final double itemExtent;
|
||||||
|
|
||||||
|
final Key center;
|
||||||
|
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
|
|
||||||
Widget _buildChildLayout() {
|
AxisDirection _getDirection(BuildContext context) {
|
||||||
|
// TODO(abarth): Consider reading direction.
|
||||||
|
switch (scrollDirection) {
|
||||||
|
case Axis.horizontal:
|
||||||
|
return AxisDirection.right;
|
||||||
|
case Axis.vertical:
|
||||||
|
return AxisDirection.down;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
final SliverChildListDelegate delegate = new SliverChildListDelegate(children);
|
final SliverChildListDelegate delegate = new SliverChildListDelegate(children);
|
||||||
|
|
||||||
if (itemExtent != null) {
|
Widget sliver;
|
||||||
return new SliverList(
|
|
||||||
|
if (itemExtent == null) {
|
||||||
|
sliver = new SliverBlock(delegate: delegate);
|
||||||
|
} else {
|
||||||
|
sliver = new SliverList(
|
||||||
delegate: delegate,
|
delegate: delegate,
|
||||||
itemExtent: itemExtent,
|
itemExtent: itemExtent,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SliverBlock(delegate: delegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Widget sliver = _buildChildLayout();
|
|
||||||
|
|
||||||
if (padding != null)
|
if (padding != null)
|
||||||
sliver = new SliverPadding(padding: padding, child: sliver);
|
sliver = new SliverPadding(padding: padding, child: sliver);
|
||||||
|
|
||||||
return new ScrollableViewport2(
|
return new ScrollableViewport2(
|
||||||
axisDirection: _getDirection(context, scrollDirection),
|
axisDirection: _getDirection(context),
|
||||||
initialScrollOffset: initialScrollOffset,
|
anchor: anchor,
|
||||||
slivers: <Widget>[ sliver ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScrollGrid extends StatelessWidget {
|
|
||||||
ScrollGrid({
|
|
||||||
Key key,
|
|
||||||
this.padding,
|
|
||||||
this.scrollDirection: Axis.vertical,
|
|
||||||
this.initialScrollOffset: 0.0,
|
|
||||||
this.gridDelegate,
|
|
||||||
this.children,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
ScrollGrid.count({
|
|
||||||
Key key,
|
|
||||||
this.padding,
|
|
||||||
this.scrollDirection: Axis.vertical,
|
|
||||||
this.initialScrollOffset: 0.0,
|
|
||||||
@required int crossAxisCount,
|
|
||||||
double mainAxisSpacing: 0.0,
|
|
||||||
double crossAxisSpacing: 0.0,
|
|
||||||
double childAspectRatio: 1.0,
|
|
||||||
this.children,
|
|
||||||
}) : gridDelegate = new SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: crossAxisCount,
|
|
||||||
mainAxisSpacing: mainAxisSpacing,
|
|
||||||
crossAxisSpacing: crossAxisSpacing,
|
|
||||||
childAspectRatio: childAspectRatio,
|
|
||||||
), super(key: key);
|
|
||||||
|
|
||||||
ScrollGrid.extent({
|
|
||||||
Key key,
|
|
||||||
this.padding,
|
|
||||||
this.scrollDirection: Axis.vertical,
|
|
||||||
this.initialScrollOffset: 0.0,
|
|
||||||
@required double maxCrossAxisExtent,
|
|
||||||
double mainAxisSpacing: 0.0,
|
|
||||||
double crossAxisSpacing: 0.0,
|
|
||||||
double childAspectRatio: 1.0,
|
|
||||||
this.children,
|
|
||||||
}) : gridDelegate = new SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: maxCrossAxisExtent,
|
|
||||||
mainAxisSpacing: mainAxisSpacing,
|
|
||||||
crossAxisSpacing: crossAxisSpacing,
|
|
||||||
childAspectRatio: childAspectRatio,
|
|
||||||
), super(key: key);
|
|
||||||
|
|
||||||
final EdgeInsets padding;
|
|
||||||
|
|
||||||
final Axis scrollDirection;
|
|
||||||
|
|
||||||
final double initialScrollOffset;
|
|
||||||
|
|
||||||
final SliverGridDelegate gridDelegate;
|
|
||||||
|
|
||||||
final List<Widget> children;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final SliverChildListDelegate delegate = new SliverChildListDelegate(children);
|
|
||||||
|
|
||||||
Widget sliver = new SliverGrid(
|
|
||||||
delegate: delegate,
|
|
||||||
gridDelegate: gridDelegate,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (padding != null)
|
|
||||||
sliver = new SliverPadding(padding: padding, child: sliver);
|
|
||||||
|
|
||||||
return new ScrollableViewport2(
|
|
||||||
axisDirection: _getDirection(context, scrollDirection),
|
|
||||||
initialScrollOffset: initialScrollOffset,
|
initialScrollOffset: initialScrollOffset,
|
||||||
|
center: center,
|
||||||
slivers: <Widget>[ sliver ],
|
slivers: <Widget>[ sliver ],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,6 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'framework.dart';
|
import 'framework.dart';
|
||||||
import 'basic.dart';
|
import 'basic.dart';
|
||||||
|
|
||||||
export 'package:flutter/rendering.dart' show
|
|
||||||
SliverGridDelegate,
|
|
||||||
SliverGridDelegateWithFixedCrossAxisCount,
|
|
||||||
SliverGridDelegateWithMaxCrossAxisExtent;
|
|
||||||
|
|
||||||
abstract class SliverChildDelegate {
|
abstract class SliverChildDelegate {
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
@ -22,23 +17,24 @@ abstract class SliverChildDelegate {
|
|||||||
|
|
||||||
Widget build(BuildContext context, int index);
|
Widget build(BuildContext context, int index);
|
||||||
|
|
||||||
/// Returns an estimate of the number of children this delegate will build.
|
bool shouldRebuild(@checked SliverChildDelegate oldDelegate);
|
||||||
///
|
|
||||||
/// Used to estimate the maximum scroll offset if [estimateMaxScrollOffset]
|
|
||||||
/// returns null.
|
|
||||||
///
|
|
||||||
/// Return null if there are an unbounded number of children or if it would
|
|
||||||
/// be too difficult to estimate the number of children.
|
|
||||||
int get estimatedChildCount => null;
|
|
||||||
|
|
||||||
double estimateMaxScrollOffset(
|
int get childCount;
|
||||||
|
|
||||||
|
double estimateScrollOffsetExtent(
|
||||||
int firstIndex,
|
int firstIndex,
|
||||||
int lastIndex,
|
int lastIndex,
|
||||||
double leadingScrollOffset,
|
double leadingScrollOffset,
|
||||||
double trailingScrollOffset,
|
double trailingScrollOffset,
|
||||||
) => null;
|
) {
|
||||||
|
final int childCount = this.childCount;
|
||||||
bool shouldRebuild(@checked SliverChildDelegate oldDelegate);
|
if (lastIndex == childCount - 1)
|
||||||
|
return trailingScrollOffset;
|
||||||
|
final int reifiedCount = lastIndex - firstIndex + 1;
|
||||||
|
final double averageExtent = (trailingScrollOffset - leadingScrollOffset) / reifiedCount;
|
||||||
|
final int remainingCount = childCount - lastIndex - 1;
|
||||||
|
return trailingScrollOffset + averageExtent * remainingCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ///
|
// ///
|
||||||
@ -68,13 +64,13 @@ class SliverChildListDelegate extends SliverChildDelegate {
|
|||||||
return children[index];
|
return children[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
int get estimatedChildCount => children.length;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRebuild(@checked SliverChildListDelegate oldDelegate) {
|
bool shouldRebuild(@checked SliverChildListDelegate oldDelegate) {
|
||||||
return children != oldDelegate.children;
|
return children != oldDelegate.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get childCount => children.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
|
abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
|
||||||
@ -93,22 +89,6 @@ abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
|
|||||||
@override
|
@override
|
||||||
RenderSliverMultiBoxAdaptor createRenderObject(BuildContext context);
|
RenderSliverMultiBoxAdaptor createRenderObject(BuildContext context);
|
||||||
|
|
||||||
double estimateMaxScrollOffset(
|
|
||||||
SliverConstraints constraints,
|
|
||||||
int firstIndex,
|
|
||||||
int lastIndex,
|
|
||||||
double leadingScrollOffset,
|
|
||||||
double trailingScrollOffset,
|
|
||||||
) {
|
|
||||||
assert(lastIndex >= firstIndex);
|
|
||||||
return delegate.estimateMaxScrollOffset(
|
|
||||||
firstIndex,
|
|
||||||
lastIndex,
|
|
||||||
leadingScrollOffset,
|
|
||||||
trailingScrollOffset,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void debugFillDescription(List<String> description) {
|
void debugFillDescription(List<String> description) {
|
||||||
super.debugFillDescription(description);
|
super.debugFillDescription(description);
|
||||||
@ -150,44 +130,6 @@ class SliverList extends SliverMultiBoxAdaptorWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SliverGrid extends SliverMultiBoxAdaptorWidget {
|
|
||||||
SliverGrid({
|
|
||||||
Key key,
|
|
||||||
@required SliverChildDelegate delegate,
|
|
||||||
@required this.gridDelegate,
|
|
||||||
}) : super(key: key, delegate: delegate);
|
|
||||||
|
|
||||||
final SliverGridDelegate gridDelegate;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RenderSliverGrid createRenderObject(BuildContext context) {
|
|
||||||
final SliverMultiBoxAdaptorElement element = context;
|
|
||||||
return new RenderSliverGrid(childManager: element, gridDelegate: gridDelegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void updateRenderObject(BuildContext context, RenderSliverGrid renderObject) {
|
|
||||||
renderObject.gridDelegate = gridDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
double estimateMaxScrollOffset(
|
|
||||||
SliverConstraints constraints,
|
|
||||||
int firstIndex,
|
|
||||||
int lastIndex,
|
|
||||||
double leadingScrollOffset,
|
|
||||||
double trailingScrollOffset,
|
|
||||||
) {
|
|
||||||
return super.estimateMaxScrollOffset(
|
|
||||||
constraints,
|
|
||||||
firstIndex,
|
|
||||||
lastIndex,
|
|
||||||
leadingScrollOffset,
|
|
||||||
trailingScrollOffset,
|
|
||||||
) ?? gridDelegate.estimateMaxScrollOffset(constraints, delegate.estimatedChildCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SliverMultiBoxAdaptorElement extends RenderObjectElement implements RenderSliverBoxChildManager {
|
class SliverMultiBoxAdaptorElement extends RenderObjectElement implements RenderSliverBoxChildManager {
|
||||||
SliverMultiBoxAdaptorElement(SliverMultiBoxAdaptorWidget widget) : super(widget);
|
SliverMultiBoxAdaptorElement(SliverMultiBoxAdaptorWidget widget) : super(widget);
|
||||||
|
|
||||||
@ -299,41 +241,19 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
double _extrapolateMaxScrollOffset(
|
|
||||||
int firstIndex,
|
|
||||||
int lastIndex,
|
|
||||||
double leadingScrollOffset,
|
|
||||||
double trailingScrollOffset,
|
|
||||||
) {
|
|
||||||
final int childCount = widget.delegate.estimatedChildCount;
|
|
||||||
if (childCount == null)
|
|
||||||
return double.INFINITY;
|
|
||||||
if (lastIndex == childCount - 1)
|
|
||||||
return trailingScrollOffset;
|
|
||||||
final int reifiedCount = lastIndex - firstIndex + 1;
|
|
||||||
final double averageExtent = (trailingScrollOffset - leadingScrollOffset) / reifiedCount;
|
|
||||||
final int remainingCount = childCount - lastIndex - 1;
|
|
||||||
return trailingScrollOffset + averageExtent * remainingCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, {
|
double estimateScrollOffsetExtent({
|
||||||
int firstIndex,
|
int firstIndex,
|
||||||
int lastIndex,
|
int lastIndex,
|
||||||
double leadingScrollOffset,
|
double leadingScrollOffset,
|
||||||
double trailingScrollOffset,
|
double trailingScrollOffset,
|
||||||
}) {
|
}) {
|
||||||
return widget.estimateMaxScrollOffset(
|
assert(lastIndex >= firstIndex);
|
||||||
constraints,
|
return widget.delegate.estimateScrollOffsetExtent(
|
||||||
firstIndex,
|
firstIndex,
|
||||||
lastIndex,
|
lastIndex,
|
||||||
leadingScrollOffset,
|
leadingScrollOffset,
|
||||||
trailingScrollOffset,
|
trailingScrollOffset
|
||||||
) ?? _extrapolateMaxScrollOffset(
|
|
||||||
firstIndex,
|
|
||||||
lastIndex,
|
|
||||||
leadingScrollOffset,
|
|
||||||
trailingScrollOffset,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double estimateMaxScrollOffset(SliverConstraints constraints, {
|
double estimateScrollOffsetExtent({
|
||||||
int firstIndex,
|
int firstIndex,
|
||||||
int lastIndex,
|
int lastIndex,
|
||||||
double leadingScrollOffset,
|
double leadingScrollOffset,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
final Key blockKey = new Key('test');
|
final Key blockKey = new Key('test');
|
||||||
@ -121,7 +120,7 @@ void main() {
|
|||||||
expect(key.currentState.scrollOffset, 0.0);
|
expect(key.currentState.scrollOffset, 0.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('SliverBlockChildListDelegate.estimateMaxScrollOffset hits end', (WidgetTester tester) async {
|
testWidgets('SliverBlockChildListDelegate.estimateScrollOffsetExtent hits end', (WidgetTester tester) async {
|
||||||
SliverChildListDelegate delegate = new SliverChildListDelegate(<Widget>[
|
SliverChildListDelegate delegate = new SliverChildListDelegate(<Widget>[
|
||||||
new Container(),
|
new Container(),
|
||||||
new Container(),
|
new Container(),
|
||||||
@ -130,23 +129,6 @@ void main() {
|
|||||||
new Container(),
|
new Container(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await tester.pumpWidget(new ScrollableViewport2(
|
expect(delegate.estimateScrollOffsetExtent(3, 4, 25.0, 26.0), equals(26.0));
|
||||||
slivers: <Widget>[
|
|
||||||
new SliverBlock(
|
|
||||||
delegate: delegate,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
|
|
||||||
final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverBlock));
|
|
||||||
|
|
||||||
final double maxScrollOffset = element.estimateMaxScrollOffset(
|
|
||||||
null,
|
|
||||||
firstIndex: 3,
|
|
||||||
lastIndex: 4,
|
|
||||||
leadingScrollOffset: 25.0,
|
|
||||||
trailingScrollOffset: 26.0
|
|
||||||
);
|
|
||||||
expect(maxScrollOffset, equals(26.0));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,306 +0,0 @@
|
|||||||
// Copyright 2017 The Chromium 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_test/flutter_test.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
import 'states.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Empty ScrollGrid', (WidgetTester tester) async {
|
|
||||||
await tester.pumpWidget(new ScrollGrid.count(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
children: const <Widget>[],
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('ScrollGrid.count control test', (WidgetTester tester) async {
|
|
||||||
List<String> log = <String>[];
|
|
||||||
|
|
||||||
await tester.pumpWidget(new ScrollGrid.count(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
children: kStates.map((String state) {
|
|
||||||
return new GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
log.add(state);
|
|
||||||
},
|
|
||||||
child: new Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
backgroundColor: const Color(0xFF0000FF),
|
|
||||||
),
|
|
||||||
child: new Text(state),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('Arkansas')), equals(const Size(200.0, 200.0)));
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
await tester.tap(find.text(kStates[i]));
|
|
||||||
expect(log, equals(<String>[kStates[i]]));
|
|
||||||
log.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(find.text(kStates[12]), findsNothing);
|
|
||||||
expect(find.text('Nevada'), findsNothing);
|
|
||||||
|
|
||||||
await tester.scroll(find.text('Arkansas'), const Offset(0.0, -200.0));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
expect(find.text(kStates[i]), findsNothing);
|
|
||||||
|
|
||||||
for (int i = 4; i < 12; ++i) {
|
|
||||||
await tester.tap(find.text(kStates[i]));
|
|
||||||
expect(log, equals(<String>[kStates[i]]));
|
|
||||||
log.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
await tester.scroll(find.text('Delaware'), const Offset(0.0, -4000.0));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expect(find.text('Alabama'), findsNothing);
|
|
||||||
expect(find.text('Pennsylvania'), findsNothing);
|
|
||||||
|
|
||||||
expect(tester.getCenter(find.text('Tennessee')),
|
|
||||||
equals(const Point(300.0, 100.0)));
|
|
||||||
|
|
||||||
await tester.tap(find.text('Tennessee'));
|
|
||||||
expect(log, equals(<String>['Tennessee']));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
await tester.scroll(find.text('Tennessee'), const Offset(0.0, 200.0));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
await tester.tap(find.text('Tennessee'));
|
|
||||||
expect(log, equals(<String>['Tennessee']));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
await tester.tap(find.text('Pennsylvania'));
|
|
||||||
expect(log, equals(<String>['Pennsylvania']));
|
|
||||||
log.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('ScrollGrid.extent control test', (WidgetTester tester) async {
|
|
||||||
List<String> log = <String>[];
|
|
||||||
|
|
||||||
await tester.pumpWidget(new ScrollGrid.extent(
|
|
||||||
maxCrossAxisExtent: 200.0,
|
|
||||||
children: kStates.map((String state) {
|
|
||||||
return new GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
log.add(state);
|
|
||||||
},
|
|
||||||
child: new Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
backgroundColor: const Color(0xFF0000FF),
|
|
||||||
),
|
|
||||||
child: new Text(state),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('Arkansas')), equals(const Size(200.0, 200.0)));
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
await tester.tap(find.text(kStates[i]));
|
|
||||||
expect(log, equals(<String>[kStates[i]]));
|
|
||||||
log.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(find.text('Nevada'), findsNothing);
|
|
||||||
|
|
||||||
await tester.scroll(find.text('Arkansas'), const Offset(0.0, -4000.0));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expect(find.text('Alabama'), findsNothing);
|
|
||||||
|
|
||||||
expect(tester.getCenter(find.text('Tennessee')),
|
|
||||||
equals(const Point(300.0, 100.0)));
|
|
||||||
|
|
||||||
await tester.tap(find.text('Tennessee'));
|
|
||||||
expect(log, equals(<String>['Tennessee']));
|
|
||||||
log.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('ScrollGrid large scroll jump', (WidgetTester tester) async {
|
|
||||||
List<int> log = <int>[];
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
new ScrollGrid.extent(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
maxCrossAxisExtent: 200.0,
|
|
||||||
childAspectRatio: 0.75,
|
|
||||||
children: new List<Widget>.generate(80, (int i) {
|
|
||||||
return new Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
log.add(i);
|
|
||||||
return new Container(
|
|
||||||
child: new Text('$i'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('4')), equals(const Size(200.0 / 0.75, 200.0)));
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
0, 1, 2, // col 0
|
|
||||||
3, 4, 5, // col 1
|
|
||||||
6, 7, 8, // col 2
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
|
|
||||||
Scrollable2State state = tester.state(find.byType(Scrollable2));
|
|
||||||
AbsoluteScrollPosition position = state.position;
|
|
||||||
position.jumpTo(3025.0);
|
|
||||||
|
|
||||||
expect(log, isEmpty);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
33, 34, 35, // col 11
|
|
||||||
36, 37, 38, // col 12
|
|
||||||
39, 40, 41, // col 13
|
|
||||||
42, 43, 44, // col 14
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
position.jumpTo(975.0);
|
|
||||||
|
|
||||||
expect(log, isEmpty);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
9, 10, 11, // col 3
|
|
||||||
12, 13, 14, // col 4
|
|
||||||
15, 16, 17, // col 5
|
|
||||||
18, 19, 20, // col 6
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('ScrollGrid - change crossAxisCount', (WidgetTester tester) async {
|
|
||||||
List<int> log = <int>[];
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
new ScrollGrid(
|
|
||||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
),
|
|
||||||
children: new List<Widget>.generate(40, (int i) {
|
|
||||||
return new Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
log.add(i);
|
|
||||||
return new Container(
|
|
||||||
child: new Text('$i'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('4')), equals(const Size(200.0, 200.0)));
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
0, 1, 2, 3, // row 0
|
|
||||||
4, 5, 6, 7, // row 1
|
|
||||||
8, 9, 10, 11, // row 2
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
new ScrollGrid(
|
|
||||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 2,
|
|
||||||
),
|
|
||||||
children: new List<Widget>.generate(40, (int i) {
|
|
||||||
return new Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
log.add(i);
|
|
||||||
return new Container(
|
|
||||||
child: new Text('$i'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
0, 1, 2, 3, // row 0
|
|
||||||
4, 5, 6, 7, // row 1
|
|
||||||
8, 9, 10, 11, // row 2
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('3')), equals(const Size(400.0, 400.0)));
|
|
||||||
expect(find.text('4'), findsNothing);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('ScrollGrid - change maxChildCrossAxisExtent', (WidgetTester tester) async {
|
|
||||||
List<int> log = <int>[];
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
new ScrollGrid(
|
|
||||||
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: 200.0,
|
|
||||||
),
|
|
||||||
children: new List<Widget>.generate(40, (int i) {
|
|
||||||
return new Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
log.add(i);
|
|
||||||
return new Container(
|
|
||||||
child: new Text('$i'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('4')), equals(const Size(200.0, 200.0)));
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
0, 1, 2, 3, // row 0
|
|
||||||
4, 5, 6, 7, // row 1
|
|
||||||
8, 9, 10, 11, // row 2
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
new ScrollGrid(
|
|
||||||
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: 400.0,
|
|
||||||
),
|
|
||||||
children: new List<Widget>.generate(40, (int i) {
|
|
||||||
return new Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
log.add(i);
|
|
||||||
return new Container(
|
|
||||||
child: new Text('$i'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(log, equals(<int>[
|
|
||||||
0, 1, 2, 3, // row 0
|
|
||||||
4, 5, 6, 7, // row 1
|
|
||||||
8, 9, 10, 11, // row 2
|
|
||||||
]));
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
expect(tester.getSize(find.text('3')), equals(const Size(400.0, 400.0)));
|
|
||||||
expect(find.text('4'), findsNothing);
|
|
||||||
});
|
|
||||||
}
|
|
@ -5,14 +5,65 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'states.dart';
|
const List<String> _kStates = const <String>[
|
||||||
|
'Alabama',
|
||||||
|
'Alaska',
|
||||||
|
'Arizona',
|
||||||
|
'Arkansas',
|
||||||
|
'California',
|
||||||
|
'Colorado',
|
||||||
|
'Connecticut',
|
||||||
|
'Delaware',
|
||||||
|
'Florida',
|
||||||
|
'Georgia',
|
||||||
|
'Hawaii',
|
||||||
|
'Idaho',
|
||||||
|
'Illinois',
|
||||||
|
'Indiana',
|
||||||
|
'Iowa',
|
||||||
|
'Kansas',
|
||||||
|
'Kentucky',
|
||||||
|
'Louisiana',
|
||||||
|
'Maine',
|
||||||
|
'Maryland',
|
||||||
|
'Massachusetts',
|
||||||
|
'Michigan',
|
||||||
|
'Minnesota',
|
||||||
|
'Mississippi',
|
||||||
|
'Missouri',
|
||||||
|
'Montana',
|
||||||
|
'Nebraska',
|
||||||
|
'Nevada',
|
||||||
|
'New Hampshire',
|
||||||
|
'New Jersey',
|
||||||
|
'New Mexico',
|
||||||
|
'New York',
|
||||||
|
'North Carolina',
|
||||||
|
'North Dakota',
|
||||||
|
'Ohio',
|
||||||
|
'Oklahoma',
|
||||||
|
'Oregon',
|
||||||
|
'Pennsylvania',
|
||||||
|
'Rhode Island',
|
||||||
|
'South Carolina',
|
||||||
|
'South Dakota',
|
||||||
|
'Tennessee',
|
||||||
|
'Texas',
|
||||||
|
'Utah',
|
||||||
|
'Vermont',
|
||||||
|
'Virginia',
|
||||||
|
'Washington',
|
||||||
|
'West Virginia',
|
||||||
|
'Wisconsin',
|
||||||
|
'Wyoming',
|
||||||
|
];
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('ScrollView control test', (WidgetTester tester) async {
|
testWidgets('ScrollView control test', (WidgetTester tester) async {
|
||||||
List<String> log = <String>[];
|
List<String> log = <String>[];
|
||||||
|
|
||||||
await tester.pumpWidget(new ScrollView(
|
await tester.pumpWidget(new ScrollView(
|
||||||
children: kStates.map<Widget>((String state) {
|
children: _kStates.map<Widget>((String state) {
|
||||||
return new GestureDetector(
|
return new GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
log.add(state);
|
log.add(state);
|
||||||
@ -48,7 +99,7 @@ void main() {
|
|||||||
testWidgets('ScrollView restart ballistic activity out of range', (WidgetTester tester) async {
|
testWidgets('ScrollView restart ballistic activity out of range', (WidgetTester tester) async {
|
||||||
Widget buildScrollView(int n) {
|
Widget buildScrollView(int n) {
|
||||||
return new ScrollView(
|
return new ScrollView(
|
||||||
children: kStates.take(n).map<Widget>((String state) {
|
children: _kStates.take(n).map<Widget>((String state) {
|
||||||
return new Container(
|
return new Container(
|
||||||
height: 200.0,
|
height: 200.0,
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const List<String> kStates = const <String>[
|
|
||||||
'Alabama',
|
|
||||||
'Alaska',
|
|
||||||
'Arizona',
|
|
||||||
'Arkansas',
|
|
||||||
'California',
|
|
||||||
'Colorado',
|
|
||||||
'Connecticut',
|
|
||||||
'Delaware',
|
|
||||||
'Florida',
|
|
||||||
'Georgia',
|
|
||||||
'Hawaii',
|
|
||||||
'Idaho',
|
|
||||||
'Illinois',
|
|
||||||
'Indiana',
|
|
||||||
'Iowa',
|
|
||||||
'Kansas',
|
|
||||||
'Kentucky',
|
|
||||||
'Louisiana',
|
|
||||||
'Maine',
|
|
||||||
'Maryland',
|
|
||||||
'Massachusetts',
|
|
||||||
'Michigan',
|
|
||||||
'Minnesota',
|
|
||||||
'Mississippi',
|
|
||||||
'Missouri',
|
|
||||||
'Montana',
|
|
||||||
'Nebraska',
|
|
||||||
'Nevada',
|
|
||||||
'New Hampshire',
|
|
||||||
'New Jersey',
|
|
||||||
'New Mexico',
|
|
||||||
'New York',
|
|
||||||
'North Carolina',
|
|
||||||
'North Dakota',
|
|
||||||
'Ohio',
|
|
||||||
'Oklahoma',
|
|
||||||
'Oregon',
|
|
||||||
'Pennsylvania',
|
|
||||||
'Rhode Island',
|
|
||||||
'South Carolina',
|
|
||||||
'South Dakota',
|
|
||||||
'Tennessee',
|
|
||||||
'Texas',
|
|
||||||
'Utah',
|
|
||||||
'Vermont',
|
|
||||||
'Virginia',
|
|
||||||
'Washington',
|
|
||||||
'West Virginia',
|
|
||||||
'Wisconsin',
|
|
||||||
'Wyoming',
|
|
||||||
];
|
|
Loading…
x
Reference in New Issue
Block a user