Commit 7bf3cb41 authored by Adam Barth's avatar Adam Barth

Merge pull request #1061 from abarth/generalize_grid_layout

Generalize grid layout
parents a5925149 46a178dc
......@@ -20,7 +20,10 @@ Color randomColor() {
RenderBox buildGridExample() {
List<RenderBox> children = new List<RenderBox>.generate(30, (_) => new RenderSolidColorBox(randomColor()));
return new RenderGrid(children: children, maxChildExtent: 100.0);
return new RenderGrid(
children: children,
delegate: new MaxTileWidthGridDelegate(maxTileWidth: 100.0)
);
}
main() => new RenderingFlutterBinding(root: buildGridExample());
......@@ -62,7 +62,7 @@ class AdaptiveItem {
}
class MediaQueryExample extends StatelessComponent {
static const double _maxChildExtent = 150.0;
static const double _maxTileWidth = 150.0;
static const double _gridViewBreakpoint = 450.0;
Widget _buildBody(BuildContext context) {
......@@ -78,9 +78,9 @@ class MediaQueryExample extends StatelessComponent {
} else {
return new Block(
<Widget>[
new Grid(
new MaxTileWidthGrid(
items.map((AdaptiveItem item) => item.toCard()).toList(),
maxChildExtent: _maxChildExtent
maxTileWidth: _maxTileWidth
)
]
);
......
......@@ -43,8 +43,17 @@ class EdgeDims {
/// Whether every dimension is non-negative.
bool get isNonNegative => top >= 0.0 && right >= 0.0 && bottom >= 0.0 && left >= 0.0;
/// The size that this edge dims would occupy with an empty interior.
ui.Size get collapsedSize => new ui.Size(left + right, top + bottom);
/// The total offset in the vertical direction.
double get horizontal => left + right;
/// The total offset in the horizontal direction.
double get vertical => top + bottom;
/// The size that this EdgeDims would occupy with an empty interior.
ui.Size get collapsedSize => new ui.Size(horizontal, vertical);
/// An EdgeDims with top and bottom as well as left and right flipped.
EdgeDims get flipped => new EdgeDims.TRBL(bottom, left, top, right);
ui.Rect inflateRect(ui.Rect rect) {
return new ui.Rect.fromLTRB(rect.left - left, rect.top - top, rect.right + right, rect.bottom + bottom);
......
......@@ -374,7 +374,7 @@ abstract class RenderBox extends RenderObject {
return constraints.constrainWidth(0.0);
}
/// Return the minimum height that this box could be without failing to render
/// Return the minimum height that this box could be without failing to paint
/// its contents within itself.
///
/// Override in subclasses that implement [performLayout].
......
......@@ -33,6 +33,7 @@ export 'package:flutter/rendering.dart' show
FontWeight,
FractionalOffset,
Gradient,
GridDelegate,
HitTestBehavior,
ImageFit,
ImageRepeat,
......@@ -1125,21 +1126,125 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
}
}
abstract class GridRenderObjectWidgetBase extends MultiChildRenderObjectWidget {
GridRenderObjectWidgetBase({
List<Widget> children,
Key key
}) : super(key: key, children: children) {
_delegate = createDelegate();
}
GridDelegate _delegate;
/// The delegate that controls the layout of the children.
GridDelegate createDelegate();
RenderGrid createRenderObject() => new RenderGrid(delegate: _delegate);
void updateRenderObject(RenderGrid renderObject, GridRenderObjectWidgetBase oldWidget) {
renderObject.delegate = _delegate;
}
}
/// Uses the grid layout algorithm for its children.
///
/// For details about the grid layout algorithm, see [RenderGrid].
class Grid extends MultiChildRenderObjectWidget {
Grid(List<Widget> children, { Key key, this.maxChildExtent })
class CustomGrid extends GridRenderObjectWidgetBase {
CustomGrid(List<Widget> children, { Key key, this.delegate })
: super(key: key, children: children) {
assert(maxChildExtent != null);
assert(delegate != null);
}
final double maxChildExtent;
/// The delegate that controls the layout of the children.
final GridDelegate delegate;
RenderGrid createRenderObject() => new RenderGrid(maxChildExtent: maxChildExtent);
GridDelegate createDelegate() => delegate;
}
/// Uses a grid layout with a fixed column count.
///
/// For details about the grid layout algorithm, see [MaxTileWidthGridDelegate].
class FixedColumnCountGrid extends GridRenderObjectWidgetBase {
FixedColumnCountGrid(List<Widget> children, {
Key key,
this.columnCount,
this.tileAspectRatio: 1.0,
this.padding: EdgeDims.zero
}) : super(key: key, children: children) {
assert(columnCount != null);
}
/// The number of columns in the grid.
final int columnCount;
void updateRenderObject(RenderGrid renderObject, Grid oldWidget) {
renderObject.maxChildExtent = maxChildExtent;
/// The ratio of the width to the height of each tile in the grid.
final double tileAspectRatio;
/// The amount of padding to apply to each child.
final EdgeDims padding;
FixedColumnCountGridDelegate createDelegate() {
return new FixedColumnCountGridDelegate(
columnCount: columnCount,
tileAspectRatio: tileAspectRatio,
padding: padding
);
}
}
/// Uses a grid layout with a max tile width.
///
/// For details about the grid layout algorithm, see [MaxTileWidthGridDelegate].
class MaxTileWidthGrid extends GridRenderObjectWidgetBase {
MaxTileWidthGrid(List<Widget> children, {
Key key,
this.maxTileWidth,
this.tileAspectRatio: 1.0,
this.padding: EdgeDims.zero
}) : super(key: key, children: children) {
assert(maxTileWidth != null);
}
/// The maximum width of a tile in the grid.
final double maxTileWidth;
/// The ratio of the width to the height of each tile in the grid.
final double tileAspectRatio;
/// The amount of padding to apply to each child.
final EdgeDims padding;
MaxTileWidthGridDelegate createDelegate() {
return new MaxTileWidthGridDelegate(
maxTileWidth: maxTileWidth,
tileAspectRatio: tileAspectRatio,
padding: padding
);
}
}
/// Supplies per-child data to the grid's [GridDelegate].
class GridPlacementData<DataType, WidgetType extends RenderObjectWidget> extends ParentDataWidget<WidgetType> {
GridPlacementData({ Key key, this.placementData, Widget child })
: super(key: key, child: child);
/// Opaque data passed to the getChildPlacement method of the grid's [GridDelegate].
final DataType placementData;
void applyParentData(RenderObject renderObject) {
assert(renderObject.parentData is GridParentData);
final GridParentData parentData = renderObject.parentData;
if (parentData.placementData != placementData) {
parentData.placementData = placementData;
AbstractNode targetParent = renderObject.parent;
if (targetParent is RenderObject)
targetParent.markNeedsLayout();
}
}
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('placementData: $placementData');
}
}
......
......@@ -16,7 +16,10 @@ void main() {
new RenderDecoratedBox(decoration: new BoxDecoration())
];
RenderGrid grid = new RenderGrid(children: children, maxChildExtent: 100.0);
RenderGrid grid = new RenderGrid(
children: children,
delegate: new MaxTileWidthGridDelegate(maxTileWidth: 100.0)
);
layout(grid, constraints: const BoxConstraints(maxWidth: 200.0));
children.forEach((RenderBox child) {
......@@ -28,7 +31,7 @@ void main() {
expect(grid.size.height, equals(200.0), reason: "grid height");
expect(grid.needsLayout, equals(false));
grid.maxChildExtent = 60.0;
grid.delegate = new MaxTileWidthGridDelegate(maxTileWidth: 60.0);
expect(grid.needsLayout, equals(true));
pumpFrame();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment