Commit ba3930cc authored by Hans Muller's avatar Hans Muller

Changed grid layout padding and inter row/column spacing

parent 5960a134
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math' as math;
import 'dart:typed_data'; import 'dart:typed_data';
import 'box.dart'; import 'box.dart';
...@@ -25,8 +26,8 @@ bool _debugIsMonotonic(List<double> offsets) { ...@@ -25,8 +26,8 @@ bool _debugIsMonotonic(List<double> offsets) {
} }
List<double> _generateRegularOffsets(int count, double size) { List<double> _generateRegularOffsets(int count, double size) {
int length = count + 1; final int length = count + 1;
List<double> result = new Float64List(length); final List<double> result = new Float64List(length);
for (int i = 0; i < length; ++i) for (int i = 0; i < length; ++i)
result[i] = i * size; result[i] = i * size;
return result; return result;
...@@ -37,11 +38,15 @@ class GridSpecification { ...@@ -37,11 +38,15 @@ class GridSpecification {
GridSpecification.fromOffsets({ GridSpecification.fromOffsets({
this.columnOffsets, this.columnOffsets,
this.rowOffsets, this.rowOffsets,
this.columnSpacing: 0.0,
this.rowSpacing: 0.0,
this.padding: EdgeDims.zero this.padding: EdgeDims.zero
}) { }) {
assert(_debugIsMonotonic(columnOffsets)); assert(_debugIsMonotonic(columnOffsets));
assert(_debugIsMonotonic(rowOffsets)); assert(_debugIsMonotonic(rowOffsets));
assert(padding != null); assert(columnSpacing != null && columnSpacing >= 0.0);
assert(rowSpacing != null && rowSpacing >= 0.0);
assert(padding != null && padding.isNonNegative);
} }
/// Creates a grid specification containing a certain number of equally sized tiles. /// Creates a grid specification containing a certain number of equally sized tiles.
...@@ -50,42 +55,50 @@ class GridSpecification { ...@@ -50,42 +55,50 @@ class GridSpecification {
double tileHeight, double tileHeight,
int columnCount, int columnCount,
int rowCount, int rowCount,
this.rowSpacing: 0.0,
this.columnSpacing: 0.0,
this.padding: EdgeDims.zero this.padding: EdgeDims.zero
}) : columnOffsets = _generateRegularOffsets(columnCount, tileWidth), }) : columnOffsets = _generateRegularOffsets(columnCount, tileWidth),
rowOffsets = _generateRegularOffsets(rowCount, tileHeight) { rowOffsets = _generateRegularOffsets(rowCount, tileHeight) {
assert(_debugIsMonotonic(columnOffsets)); assert(_debugIsMonotonic(columnOffsets));
assert(_debugIsMonotonic(rowOffsets)); assert(_debugIsMonotonic(rowOffsets));
assert(padding != null); assert(padding != null && padding.isNonNegative);
} }
/// The offsets of the column boundaries in the grid. /// The offsets of the column boundaries in the grid.
/// ///
/// The first offset is the offset of the left edge of the left-most column /// The first offset is the offset of the left edge of the left-most column
/// from the left edge of the interior of the grid's padding (usually 0.0). /// from the left edge of the interior of the grid's padding (0.0 if the padding
/// The last offset is the offset of the right edge of the right-most column /// is EdgeOffsets.zero). The last offset is the offset of the right edge of
/// from the left edge of the interior of the grid's padding. /// the right-most column from the left edge of the interior of the grid's padding.
/// ///
/// If there are n columns in the grid, there should be n + 1 entries in this /// If there are n columns in the grid, there should be n + 1 entries in this
/// list (because there's an entry before the first column and after the last /// list. The right edge of the last column is defined as columnOffsets(n), i.e.
/// column). /// the left edge of an extra column.
final List<double> columnOffsets; final List<double> columnOffsets;
/// The offsets of the row boundaries in the grid. /// The offsets of the row boundaries in the grid.
/// ///
/// The first offset is the offset of the top edge of the top-most row from /// The first offset is the offset of the top edge of the top-most row from
/// the top edge of the interior of the grid's padding (usually 0.0). The /// the top edge of the interior of the grid's padding (usually if the padding
/// last offset is the offset of the bottom edge of the bottom-most column /// is EdgeOffsets.zero). The last offset is the offset of the bottom edge of
/// from the top edge of the interior of the grid's padding. /// the bottom-most column from the top edge of the interior of the grid's padding.
/// ///
/// If there are n rows in the grid, there should be n + 1 entries in this /// If there are n rows in the grid, there should be n + 1 entries in this
/// list (because there's an entry before the first row and after the last /// list. The bottom edge of the last row is defined as rowOffsets(n), i.e.
/// row). /// the top edge of an extra row.
final List<double> rowOffsets; final List<double> rowOffsets;
/// The vertical distance between rows.
final double rowSpacing;
/// The horizontal distance between columns.
final double columnSpacing;
/// The interior padding of the grid. /// The interior padding of the grid.
/// ///
/// The grid's size encloses the rows and columns and is then inflated by the /// The grid's size encloses the spaced rows and columns and is then inflated
/// padding. /// by the padding.
final EdgeDims padding; final EdgeDims padding;
/// The size of the grid. /// The size of the grid.
...@@ -104,14 +117,12 @@ class GridChildPlacement { ...@@ -104,14 +117,12 @@ class GridChildPlacement {
this.column, this.column,
this.row, this.row,
this.columnSpan: 1, this.columnSpan: 1,
this.rowSpan: 1, this.rowSpan: 1
this.padding: EdgeDims.zero
}) { }) {
assert(column != null); assert(column != null && column >= 0);
assert(row != null); assert(row != null && row >= 0);
assert(columnSpan != null); assert(columnSpan != null && columnSpan > 0);
assert(rowSpan != null); assert(rowSpan != null && rowSpan > 0);
assert(padding != null);
} }
/// The column in which to place the child. /// The column in which to place the child.
...@@ -125,9 +136,6 @@ class GridChildPlacement { ...@@ -125,9 +136,6 @@ class GridChildPlacement {
/// How many rows the child should span. /// How many rows the child should span.
final int rowSpan; final int rowSpan;
/// How much the child should be inset from the column and row boundaries.
final EdgeDims padding;
} }
/// An abstract interface to control the layout of a [RenderGrid]. /// An abstract interface to control the layout of a [RenderGrid].
...@@ -172,32 +180,53 @@ abstract class GridDelegate { ...@@ -172,32 +180,53 @@ abstract class GridDelegate {
/// A [GridDelegate] the places its children in order throughout the grid. /// A [GridDelegate] the places its children in order throughout the grid.
abstract class GridDelegateWithInOrderChildPlacement extends GridDelegate { abstract class GridDelegateWithInOrderChildPlacement extends GridDelegate {
GridDelegateWithInOrderChildPlacement({ this.padding: EdgeDims.zero }); GridDelegateWithInOrderChildPlacement({
this.columnSpacing: 0.0,
this.rowSpacing: 0.0,
this.padding: EdgeDims.zero
}) {
assert(columnSpacing != null && columnSpacing >= 0.0);
assert(rowSpacing != null && rowSpacing >= 0.0);
assert(padding != null && padding.isNonNegative);
}
/// The horizontal distance between columns.
final double columnSpacing;
/// The vertical distance between rows.
final double rowSpacing;
/// The amount of padding to apply to each child. // Insets for the entire grid.
final EdgeDims padding; final EdgeDims padding;
GridChildPlacement getChildPlacement(GridSpecification specification, int index, Object placementData) { GridChildPlacement getChildPlacement(GridSpecification specification, int index, Object placementData) {
int columnCount = specification.columnOffsets.length - 1; final int columnCount = specification.columnOffsets.length - 1;
return new GridChildPlacement( return new GridChildPlacement(
column: index % columnCount, column: index % columnCount,
row: index ~/ columnCount, row: index ~/ columnCount
padding: padding
); );
} }
bool shouldRelayout(GridDelegateWithInOrderChildPlacement oldDelegate) { bool shouldRelayout(GridDelegateWithInOrderChildPlacement oldDelegate) {
return padding != oldDelegate.padding; return columnSpacing != oldDelegate.columnSpacing
|| rowSpacing != oldDelegate.rowSpacing
|| padding != oldDelegate.padding;
} }
} }
/// A [GridDelegate] that divides the grid's width evenly amount a fixed number of columns. /// A [GridDelegate] that divides the grid's width evenly amount a fixed number of columns.
class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement { class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement {
FixedColumnCountGridDelegate({ FixedColumnCountGridDelegate({
this.columnCount, this.columnCount,
this.tileAspectRatio: 1.0, double columnSpacing: 0.0,
EdgeDims padding: EdgeDims.zero double rowSpacing: 0.0,
}) : super(padding: padding); EdgeDims padding: EdgeDims.zero,
this.tileAspectRatio: 1.0
}) : super(columnSpacing: columnSpacing, rowSpacing: rowSpacing, padding: padding) {
assert(columnCount != null && columnCount >= 0);
assert(tileAspectRatio != null && tileAspectRatio > 0.0);
}
/// The number of columns in the grid. /// The number of columns in the grid.
final int columnCount; final int columnCount;
...@@ -208,14 +237,16 @@ class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement ...@@ -208,14 +237,16 @@ class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement
GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) { GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
assert(constraints.maxWidth < double.INFINITY); assert(constraints.maxWidth < double.INFINITY);
int rowCount = (childCount / columnCount).ceil(); int rowCount = (childCount / columnCount).ceil();
double tileWidth = constraints.maxWidth / columnCount; double tileWidth = math.max(0.0, constraints.maxWidth - padding.horizontal + columnSpacing) / columnCount;
double tileHeight = tileWidth / tileAspectRatio; double tileHeight = tileWidth / tileAspectRatio;
return new GridSpecification.fromRegularTiles( return new GridSpecification.fromRegularTiles(
tileWidth: tileWidth, tileWidth: tileWidth,
tileHeight: tileHeight, tileHeight: tileHeight,
columnCount: columnCount, columnCount: columnCount,
rowCount: rowCount, rowCount: rowCount,
padding: padding.flipped columnSpacing: columnSpacing,
rowSpacing: rowSpacing,
padding: padding
); );
} }
...@@ -246,8 +277,13 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement { ...@@ -246,8 +277,13 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement {
MaxTileWidthGridDelegate({ MaxTileWidthGridDelegate({
this.maxTileWidth, this.maxTileWidth,
this.tileAspectRatio: 1.0, this.tileAspectRatio: 1.0,
double columnSpacing: 0.0,
double rowSpacing: 0.0,
EdgeDims padding: EdgeDims.zero EdgeDims padding: EdgeDims.zero
}) : super(padding: padding); }) : super(columnSpacing: columnSpacing, rowSpacing: rowSpacing, padding: padding) {
assert(maxTileWidth != null && maxTileWidth >= 0.0);
assert(tileAspectRatio != null && tileAspectRatio > 0.0);
}
/// The maximum width of a tile in the grid. /// The maximum width of a tile in the grid.
final double maxTileWidth; final double maxTileWidth;
...@@ -257,7 +293,7 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement { ...@@ -257,7 +293,7 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement {
GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) { GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
assert(constraints.maxWidth < double.INFINITY); assert(constraints.maxWidth < double.INFINITY);
double gridWidth = constraints.maxWidth; final double gridWidth = math.max(0.0, constraints.maxWidth - padding.horizontal);
int columnCount = (gridWidth / maxTileWidth).ceil(); int columnCount = (gridWidth / maxTileWidth).ceil();
int rowCount = (childCount / columnCount).ceil(); int rowCount = (childCount / columnCount).ceil();
double tileWidth = gridWidth / columnCount; double tileWidth = gridWidth / columnCount;
...@@ -267,7 +303,9 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement { ...@@ -267,7 +303,9 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement {
tileHeight: tileHeight, tileHeight: tileHeight,
columnCount: columnCount, columnCount: columnCount,
rowCount: rowCount, rowCount: rowCount,
padding: padding.flipped columnSpacing: columnSpacing,
rowSpacing: rowSpacing,
padding: padding
); );
} }
...@@ -411,14 +449,14 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> { ...@@ -411,14 +449,14 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
void performLayout() { void performLayout() {
_updateGridSpecification(); _updateGridSpecification();
Size gridSize = _specification.gridSize; final Size gridSize = _specification.gridSize;
size = constraints.constrain(gridSize); size = constraints.constrain(gridSize);
if (callback != null) if (callback != null)
invokeLayoutCallback(callback); invokeLayoutCallback(callback);
double gridTopPadding = _specification.padding.top; final double gridTopPadding = _specification.padding.top;
double gridLeftPadding = _specification.padding.left; final double gridLeftPadding = _specification.padding.left;
int childIndex = virtualChildBase; int childIndex = virtualChildBase;
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
...@@ -435,8 +473,8 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> { ...@@ -435,8 +473,8 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
double tileTop = _specification.rowOffsets[placement.row] + gridTopPadding; double tileTop = _specification.rowOffsets[placement.row] + gridTopPadding;
double tileBottom = _specification.rowOffsets[placement.row + placement.rowSpan] + gridTopPadding; double tileBottom = _specification.rowOffsets[placement.row + placement.rowSpan] + gridTopPadding;
double childWidth = tileRight - tileLeft - placement.padding.horizontal; double childWidth = math.max(0.0, tileRight - tileLeft - _specification.columnSpacing);
double childHeight = tileBottom - tileTop - placement.padding.vertical; double childHeight = math.max(0.0, tileBottom - tileTop - _specification.rowSpacing);
child.layout(new BoxConstraints( child.layout(new BoxConstraints(
minWidth: childWidth, minWidth: childWidth,
...@@ -445,11 +483,7 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> { ...@@ -445,11 +483,7 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
maxHeight: childHeight maxHeight: childHeight
)); ));
childParentData.offset = new Offset( childParentData.offset = new Offset(tileLeft, tileTop);
tileLeft + placement.padding.left,
tileTop + placement.padding.top
);
childIndex += 1; childIndex += 1;
assert(child.parentData == childParentData); assert(child.parentData == childParentData);
......
...@@ -22,6 +22,7 @@ export 'package:flutter/rendering.dart' show ...@@ -22,6 +22,7 @@ export 'package:flutter/rendering.dart' show
FlexJustifyContent, FlexJustifyContent,
FractionalOffsetTween, FractionalOffsetTween,
GridDelegate, GridDelegate,
GridSpecification,
HitTestBehavior, HitTestBehavior,
MaxTileWidthGridDelegate, MaxTileWidthGridDelegate,
MultiChildLayoutDelegate, MultiChildLayoutDelegate,
...@@ -1192,6 +1193,8 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase { ...@@ -1192,6 +1193,8 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase {
Key key, Key key,
List<Widget> children: _emptyWidgetList, List<Widget> children: _emptyWidgetList,
this.columnCount, this.columnCount,
this.columnSpacing,
this.rowSpacing,
this.tileAspectRatio: 1.0, this.tileAspectRatio: 1.0,
this.padding: EdgeDims.zero this.padding: EdgeDims.zero
}) : super(key: key, children: children) { }) : super(key: key, children: children) {
...@@ -1201,6 +1204,12 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase { ...@@ -1201,6 +1204,12 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase {
/// The number of columns in the grid. /// The number of columns in the grid.
final int columnCount; final int columnCount;
/// The horizontal distance between columns.
final double columnSpacing;
/// The vertical distance between rows.
final double rowSpacing;
/// The ratio of the width to the height of each tile in the grid. /// The ratio of the width to the height of each tile in the grid.
final double tileAspectRatio; final double tileAspectRatio;
...@@ -1210,6 +1219,8 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase { ...@@ -1210,6 +1219,8 @@ class FixedColumnCountGrid extends GridRenderObjectWidgetBase {
FixedColumnCountGridDelegate createDelegate() { FixedColumnCountGridDelegate createDelegate() {
return new FixedColumnCountGridDelegate( return new FixedColumnCountGridDelegate(
columnCount: columnCount, columnCount: columnCount,
columnSpacing: columnSpacing,
rowSpacing: rowSpacing,
tileAspectRatio: tileAspectRatio, tileAspectRatio: tileAspectRatio,
padding: padding padding: padding
); );
...@@ -1224,6 +1235,8 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase { ...@@ -1224,6 +1235,8 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase {
Key key, Key key,
List<Widget> children: _emptyWidgetList, List<Widget> children: _emptyWidgetList,
this.maxTileWidth, this.maxTileWidth,
this.columnSpacing,
this.rowSpacing,
this.tileAspectRatio: 1.0, this.tileAspectRatio: 1.0,
this.padding: EdgeDims.zero this.padding: EdgeDims.zero
}) : super(key: key, children: children) { }) : super(key: key, children: children) {
...@@ -1236,6 +1249,12 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase { ...@@ -1236,6 +1249,12 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase {
/// The ratio of the width to the height of each tile in the grid. /// The ratio of the width to the height of each tile in the grid.
final double tileAspectRatio; final double tileAspectRatio;
/// The horizontal distance between columns.
final double columnSpacing;
/// The vertical distance between rows.
final double rowSpacing;
/// The amount of padding to apply to each child. /// The amount of padding to apply to each child.
final EdgeDims padding; final EdgeDims padding;
...@@ -1243,6 +1262,8 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase { ...@@ -1243,6 +1262,8 @@ class MaxTileWidthGrid extends GridRenderObjectWidgetBase {
return new MaxTileWidthGridDelegate( return new MaxTileWidthGridDelegate(
maxTileWidth: maxTileWidth, maxTileWidth: maxTileWidth,
tileAspectRatio: tileAspectRatio, tileAspectRatio: tileAspectRatio,
columnSpacing: columnSpacing,
rowSpacing: rowSpacing,
padding: padding padding: padding
); );
} }
......
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