Skip to content

Commit 51594fe

Browse files
authored
Merge pull request #69 from cheonjaeung/fixed-size
[WIP] Add FixedSize cell strategy
2 parents 5de159c + 7e189d8 commit 51594fe

21 files changed

+841
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This library can be simpler solution for small grid UI.
1515
There are benefits of this library:
1616

1717
- **Similar API to LazyGrid**: The GridLayout's APIs are designed to provide similar development experience to LazyGrid.
18-
- **Easy to implement adaptive grid**: There are _"Fixed"_ and _"Adaptive"_ for grid layout management like LazyGrid.
18+
- **Easy to implement various grid**: There are _"Fixed"_, _"Adaptive"_ and _"FixedSize"_ for grid layout management like LazyGrid.
1919
Like LazyGrid, it eliminates dealing with different screen sizes.
2020
- **Simple to use as a part of LazyList**: The GridLayout is not lazy layout. It can be simply placed in lazy layouts.
2121
If only a portion of the full layout is grid, No need to use LazyGrid with span size for full layout.

docs/cell-strategy.md

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
All grid layout composables take a cell strategy parameter called `SimpleGridCells`.
44
`SimpleGridCells` defines the number of cells and the size of each cell.
55

6-
There are 2 types of cell strategy, `Fixed` and `Adaptive`.
7-
They are similar to LazyGrid's `Fixed` and `Adaptive`.
6+
There are several types of cell strategy, `Fixed`, `Adaptive` and `FixedSize`.
7+
They are similar to LazyGrid's `GridCells.Fixed`, `GridCells.Adaptive` and `GridCells.FixedSize`.
88

99
## Fixed
1010

@@ -94,9 +94,51 @@ And each cells will have 1/3 of 400dp (about 133.333dp) width or height.
9494
If the grid size is expanded to 600dp, the number of cells on each line will be changed to 5
9595
and each cell's size will be 120dp.
9696

97+
## FixedSize
98+
99+
`SimpleGridCells.FixedSize` is a cell strategy for as many cells as possible with exact size.
100+
101+
The API of `FixedSize` looks like this:
102+
103+
```kotlin
104+
class FixedSize(
105+
private val size: Dp,
106+
private val fill: Boolean = true
107+
) : SimpleGridCells
108+
```
109+
110+
There is a parameter called `size`. This is the size of each cell should have.
111+
The `size` must be a positive size. If the size is 0 or below, it occurs an exception.
112+
If the `size` is bigger than container's size, the cell will have the same size to the container.
113+
114+
!!! note
115+
For information about `fill` parameter, read [Fill Option](#fill-option) section.
116+
117+
For example, a grid has 400dp width or height and `FixedSize(120.dp)` is applied.
118+
119+
```kotlin
120+
HorizontalGrid(
121+
rows = SimpleGridCells.FixedSize(120.dp),
122+
modifier = Modifier.height(400.dp)
123+
) { /* content */ }
124+
125+
VerticalGrid(
126+
columns = SimpleGridCells.FixedSize(120.dp),
127+
modifier = Modifier.width(400.dp)
128+
) { /* content */ }
129+
```
130+
131+
![fixed-size-example](./images/fixedsize-example.png)
132+
133+
The grid will have 3 cells on each line and the remaining space will not be used.
134+
If the grid size is expanded to 600dp, the number of cells on each line will be changed to 5.
135+
136+
In other case, `FixedSize(300.dp)` for `VerticalGrid(Modifier.width(200.dp))` means that there
137+
will be only one column and the cell will have 200dp width.
138+
97139
## Fill Option
98140

99-
Both `Fixed` and `Adaptive` have a optional parameter named `fill`.
141+
All cell strategy classes have a optional parameter named `fill`.
100142
The `fill` parameter determines that grid's item composable should fill grid cell's size.
101143

102144
When `fill` is true, grid layout forces item composable to have width or height to fit cell's maximum width or height.

docs/images/fixedsize-example.png

15.5 KB
Loading

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This library can be simpler solution for small grid UI.
1111
There are benefits of this library:
1212

1313
- **Similar API to LazyGrid**: The GridLayout's APIs are designed to provide similar development experience to LazyGrid.
14-
- **Easy to implement adaptive grid**: There are _"Fixed"_ and _"Adaptive"_ for grid layout management like LazyGrid.
14+
- **Easy to implement various grid**: There are _"Fixed"_, _"Adaptive"_ and _"FixedSize"_ for grid layout management like LazyGrid.
1515
Like LazyGrid, it eliminates dealing with different screen sizes.
1616
- **Simple to use as a part of LazyList**: The GridLayout is not lazy layout. It can be simply placed in lazy layouts.
1717
If only a portion of the full layout is grid, No need to use LazyGrid with span size for full layout.

grid/api/android/grid.api

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,13 @@ public final class com/cheonjaeung/compose/grid/SimpleGridCells$Fixed : com/cheo
9191
public fun hashCode ()I
9292
}
9393

94+
public final class com/cheonjaeung/compose/grid/SimpleGridCells$FixedSize : com/cheonjaeung/compose/grid/SimpleGridCells {
95+
public static final field $stable I
96+
public synthetic fun <init> (FZILkotlin/jvm/internal/DefaultConstructorMarker;)V
97+
public synthetic fun <init> (FZLkotlin/jvm/internal/DefaultConstructorMarker;)V
98+
public fun calculateCrossAxisCellSizes (Landroidx/compose/ui/unit/Density;II)Ljava/util/List;
99+
public fun equals (Ljava/lang/Object;)Z
100+
public fun fillCellSize ()Z
101+
public fun hashCode ()I
102+
}
103+

grid/api/jvm/grid.api

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,13 @@ public final class com/cheonjaeung/compose/grid/SimpleGridCells$Fixed : com/cheo
9191
public fun hashCode ()I
9292
}
9393

94+
public final class com/cheonjaeung/compose/grid/SimpleGridCells$FixedSize : com/cheonjaeung/compose/grid/SimpleGridCells {
95+
public static final field $stable I
96+
public synthetic fun <init> (FZILkotlin/jvm/internal/DefaultConstructorMarker;)V
97+
public synthetic fun <init> (FZLkotlin/jvm/internal/DefaultConstructorMarker;)V
98+
public fun calculateCrossAxisCellSizes (Landroidx/compose/ui/unit/Density;II)Ljava/util/List;
99+
public fun equals (Ljava/lang/Object;)Z
100+
public fun fillCellSize ()Z
101+
public fun hashCode ()I
102+
}
103+

grid/src/commonMain/kotlin/com/cheonjaeung/compose/grid/BoxGridMeasurePolicy.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,22 @@ private class BoxGridMeasureHelper(
189189
val horizontalSpacingPx = horizontalSpacing.roundToPx()
190190
val verticalSpacingPx = verticalSpacing.roundToPx()
191191

192-
var currentX = 0
193-
var currentY = 0
192+
var currentX = if (layoutDirection == LayoutDirection.Rtl) {
193+
val horizontalSpacingCount = (columnCount - 1).coerceAtLeast(0)
194+
val horizontalSpacingSumPx = horizontalSpacingPx * horizontalSpacingCount
195+
val contentWidth = cellWidthConstraintList.sum() + horizontalSpacingSumPx
196+
measureResult.layoutSize.width.roundToInt() - contentWidth
197+
} else {
198+
0
199+
}
194200
val xPositions = IntArray(columnCount)
195-
val yPositions = IntArray(rowCount)
196201
for (i in 0 until columnCount) {
197202
xPositions[i] = currentX
198203
currentX += cellWidthConstraintList[i] + horizontalSpacingPx
199204
}
205+
206+
var currentY = 0
207+
val yPositions = IntArray(rowCount)
200208
for (i in 0 until rowCount) {
201209
yPositions[i] = currentY
202210
currentY += cellHeightConstraintList[i] + verticalSpacingPx

grid/src/commonMain/kotlin/com/cheonjaeung/compose/grid/SimpleGridCells.kt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,67 @@ interface SimpleGridCells {
134134
return hash
135135
}
136136
}
137+
138+
/**
139+
* Make grid to have as many rows or columns as possible and each cell has exactly [size].
140+
* If [size] is bigger than container's size, the cell will have the same size to the container.
141+
*
142+
* For example, `FixedSize(20.dp)` for `VerticalGrid(Modifier.width(66.dp)` means that there
143+
* will be 3 columns and each cell will have 20dp width and 6dp is remained.
144+
*
145+
* In other case, `FixedSize(150.dp)` for `VerticalGrid(Modifier.width(100.dp)` means that there
146+
* will be only one column and the cell will have 100dp width.
147+
*
148+
* @param size The size which each cell should have.
149+
* @param fill When `true`, item composable fill cell's width or height.
150+
*/
151+
@ExperimentalGridApi
152+
class FixedSize(
153+
private val size: Dp,
154+
private val fill: Boolean = true,
155+
) : SimpleGridCells {
156+
init {
157+
if (size <= 0.dp) {
158+
throw IllegalArgumentException("FixedSize size must be a positive, but $size")
159+
}
160+
}
161+
162+
override fun Density.calculateCrossAxisCellSizes(
163+
availableSize: Int,
164+
spacing: Int
165+
): List<Int> {
166+
val cellSize = size.roundToPx()
167+
val availableSizeWithSpacing = availableSize + spacing
168+
val cellSizeWithSpacing = cellSize + spacing
169+
170+
return if (cellSizeWithSpacing < availableSizeWithSpacing) {
171+
val count = if (cellSizeWithSpacing != 0) {
172+
availableSizeWithSpacing / cellSizeWithSpacing
173+
} else {
174+
1
175+
}
176+
return List(count) { cellSize }
177+
} else {
178+
List(1) { availableSize }
179+
}
180+
}
181+
182+
override fun fillCellSize(): Boolean {
183+
return fill
184+
}
185+
186+
override fun equals(other: Any?): Boolean {
187+
if (other !is FixedSize) return false
188+
if (this.size != other.size) return false
189+
if (this.fill != other.fill) return false
190+
return true
191+
}
192+
193+
override fun hashCode(): Int {
194+
var hash = 1
195+
hash = hash * 31 + size.hashCode()
196+
hash = hash * 31 + fill.hashCode()
197+
return hash
198+
}
199+
}
137200
}

0 commit comments

Comments
 (0)