Skip to content

Commit b4cea47

Browse files
authored
Merge pull request #51 from cheonjaeung/span-modifier
Change BoxGrid span modifier to receive BoxGridItemSpanScope and returns BoxGridItemSpan
2 parents f50d07f + fde235c commit b4cea47

File tree

9 files changed

+187
-99
lines changed

9 files changed

+187
-99
lines changed

docs/span.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
The `content` composable lambda of grid layout extends `BoxGridScope`.
44
In the `BoxGridScope`, you can use `rowSpan` and `columnSpan` modifier to set span size of cell.
55

6-
The `rowSpan` and `columnSpan` modifiers take a lambda to calculate span.
7-
The lambda returns an integer value, the span size.
6+
The `span` modifiers take a lambda to calculate spans.
7+
The lambda returns a `BoxGridItemSpan` which represents row and column span size.
88
Or you can just pass `null` instead of lambda to use default span size, which is 1.
99

1010
```kotlin
1111
BoxGrid(
1212
rows = SimpleGridCells.Fixed(3),
1313
columns = SimpleGridCells.Fixed(3)
1414
) {
15-
Item(modifier = Modifier.rowSpan { 2 })
15+
Item(modifier = Modifier.span { BoxGridItemSpan(rowSpan = 2, columnSpan = 1) })
1616
Item(modifier = Modifier.column(2))
17-
Item(modifier = Modifier.row(1).column(1).columnSpan { 2 })
18-
Item(modifier = Modifier.row(2).columnSpan { 2 })
17+
Item(modifier = Modifier.row(1).column(1).span { BoxGridItemSpan(rowSpan = 1, columnSpan = 2) })
18+
Item(modifier = Modifier.row(2)span { BoxGridItemSpan(rowSpan = 1, columnSpan = 2) })
1919
}
2020
```
2121

grid/api/android/grid.api

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,43 @@
1+
public final class com/cheonjaeung/compose/grid/BoxGridItemSpan {
2+
public static final field Companion Lcom/cheonjaeung/compose/grid/BoxGridItemSpan$Companion;
3+
public static final synthetic fun box-impl (J)Lcom/cheonjaeung/compose/grid/BoxGridItemSpan;
4+
public static final fun component1-impl (J)I
5+
public static final fun component2-impl (J)I
6+
public fun equals (Ljava/lang/Object;)Z
7+
public static fun equals-impl (JLjava/lang/Object;)Z
8+
public static final fun equals-impl0 (JJ)Z
9+
public static final fun getColumnSpan-impl (J)I
10+
public static final fun getRowSpan-impl (J)I
11+
public fun hashCode ()I
12+
public static fun hashCode-impl (J)I
13+
public fun toString ()Ljava/lang/String;
14+
public static fun toString-impl (J)Ljava/lang/String;
15+
public final synthetic fun unbox-impl ()J
16+
}
17+
18+
public final class com/cheonjaeung/compose/grid/BoxGridItemSpan$Companion {
19+
}
20+
21+
public abstract interface class com/cheonjaeung/compose/grid/BoxGridItemSpanScope {
22+
public abstract fun getMaxColumnSpan ()I
23+
public abstract fun getMaxCurrentColumnSpan ()I
24+
public abstract fun getMaxCurrentRowSpan ()I
25+
public abstract fun getMaxRowSpan ()I
26+
}
27+
128
public abstract interface class com/cheonjaeung/compose/grid/BoxGridScope {
229
public abstract fun align (Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;)Landroidx/compose/ui/Modifier;
330
public abstract fun column (Landroidx/compose/ui/Modifier;I)Landroidx/compose/ui/Modifier;
4-
public abstract fun columnSpan (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
531
public abstract fun row (Landroidx/compose/ui/Modifier;I)Landroidx/compose/ui/Modifier;
6-
public abstract fun rowSpan (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
32+
public abstract fun span (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
733
}
834

935
public final class com/cheonjaeung/compose/grid/BoxGridScope$DefaultImpls {
10-
public static synthetic fun columnSpan$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
11-
public static synthetic fun rowSpan$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
36+
public static synthetic fun span$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
37+
}
38+
39+
public final class com/cheonjaeung/compose/grid/BoxGridSpanKt {
40+
public static final fun BoxGridItemSpan (II)J
1241
}
1342

1443
public abstract interface annotation class com/cheonjaeung/compose/grid/ExperimentalGridApi : java/lang/annotation/Annotation {

grid/api/jvm/grid.api

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,43 @@
1+
public final class com/cheonjaeung/compose/grid/BoxGridItemSpan {
2+
public static final field Companion Lcom/cheonjaeung/compose/grid/BoxGridItemSpan$Companion;
3+
public static final synthetic fun box-impl (J)Lcom/cheonjaeung/compose/grid/BoxGridItemSpan;
4+
public static final fun component1-impl (J)I
5+
public static final fun component2-impl (J)I
6+
public fun equals (Ljava/lang/Object;)Z
7+
public static fun equals-impl (JLjava/lang/Object;)Z
8+
public static final fun equals-impl0 (JJ)Z
9+
public static final fun getColumnSpan-impl (J)I
10+
public static final fun getRowSpan-impl (J)I
11+
public fun hashCode ()I
12+
public static fun hashCode-impl (J)I
13+
public fun toString ()Ljava/lang/String;
14+
public static fun toString-impl (J)Ljava/lang/String;
15+
public final synthetic fun unbox-impl ()J
16+
}
17+
18+
public final class com/cheonjaeung/compose/grid/BoxGridItemSpan$Companion {
19+
}
20+
21+
public abstract interface class com/cheonjaeung/compose/grid/BoxGridItemSpanScope {
22+
public abstract fun getMaxColumnSpan ()I
23+
public abstract fun getMaxCurrentColumnSpan ()I
24+
public abstract fun getMaxCurrentRowSpan ()I
25+
public abstract fun getMaxRowSpan ()I
26+
}
27+
128
public abstract interface class com/cheonjaeung/compose/grid/BoxGridScope {
229
public abstract fun align (Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;)Landroidx/compose/ui/Modifier;
330
public abstract fun column (Landroidx/compose/ui/Modifier;I)Landroidx/compose/ui/Modifier;
4-
public abstract fun columnSpan (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
531
public abstract fun row (Landroidx/compose/ui/Modifier;I)Landroidx/compose/ui/Modifier;
6-
public abstract fun rowSpan (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
32+
public abstract fun span (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
733
}
834

935
public final class com/cheonjaeung/compose/grid/BoxGridScope$DefaultImpls {
10-
public static synthetic fun columnSpan$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
11-
public static synthetic fun rowSpan$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
36+
public static synthetic fun span$default (Lcom/cheonjaeung/compose/grid/BoxGridScope;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
37+
}
38+
39+
public final class com/cheonjaeung/compose/grid/BoxGridSpanKt {
40+
public static final fun BoxGridItemSpan (II)J
1241
}
1342

1443
public abstract interface annotation class com/cheonjaeung/compose/grid/ExperimentalGridApi : java/lang/annotation/Annotation {

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

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,6 @@ private class BoxGridMeasureHelper(
112112
}
113113
}
114114

115-
private val BoxGridParentData?.rowSpanOrDefault: (GridItemSpanScope.() -> Int)
116-
get() = this?.rowSpan ?: BoxGridParentData.DefaultSpan
117-
118-
private val BoxGridParentData?.columnSpanOrDefault: (GridItemSpanScope.() -> Int)
119-
get() = this?.columnSpan ?: BoxGridParentData.DefaultSpan
120-
121115
private val BoxGridParentData?.alignmentOrDefault: Alignment
122116
get() = this?.alignment ?: defaultAlignment
123117

@@ -143,25 +137,20 @@ private class BoxGridMeasureHelper(
143137
return@fastForEachIndexed
144138
}
145139

146-
val rowSpanScope = GridItemSpanScopeImpl(
147-
maxCurrentLineSpan = rowCount - rowPosition,
148-
maxLineSpan = rowCount
140+
val spanScope = BoxGridItemSpanScopeImpl(
141+
maxCurrentRowSpan = rowCount - rowPosition,
142+
maxCurrentColumnSpan = columnCount - columnPosition,
143+
maxRowSpan = rowCount,
144+
maxColumnSpan = columnCount
149145
)
150-
val columnSpanScope = GridItemSpanScopeImpl(
151-
maxCurrentLineSpan = columnCount - columnPosition,
152-
maxLineSpan = columnCount
153-
)
154-
val rowSpanFunction = parentDataArray[index].rowSpanOrDefault
155-
val columnSpanFunction = parentDataArray[index].columnSpanOrDefault
156-
val rowSpan = rowSpanFunction(rowSpanScope)
157-
val columnSpan = columnSpanFunction(columnSpanScope)
158-
159-
require(rowSpan > 0) {
160-
"rowSpan must be bigger than zero, $rowSpan is zero or negative"
161-
}
162-
require(columnSpan > 0) {
163-
"columnSpan must be bigger than zero, $columnSpan is zero or negative"
146+
val spanFunction = parentDataArray[index]?.span
147+
val span = if (spanFunction != null) {
148+
with(spanScope) { spanFunction() }
149+
} else {
150+
BoxGridItemSpan.Default
164151
}
152+
val (rowSpan, columnSpan) = span
153+
165154
val remainingRowSpan = rowCount - rowPosition
166155
val remainingColumnSpan = columnCount - columnPosition
167156
if (rowSpan > remainingRowSpan || columnSpan > remainingColumnSpan) {

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ import androidx.compose.ui.Alignment
55
internal data class BoxGridParentData(
66
var row: Int = UNSPECIFIED_ROW,
77
var column: Int = UNSPECIFIED_COLUMN,
8-
var rowSpan: GridItemSpanScope.() -> Int = DefaultSpan,
9-
var columnSpan: GridItemSpanScope.() -> Int = DefaultSpan,
8+
var span: (BoxGridItemSpanScope.() -> BoxGridItemSpan)? = null,
109
var alignment: Alignment? = null
1110
) {
1211
companion object {
1312
internal const val UNSPECIFIED_ROW: Int = -1
1413
internal const val UNSPECIFIED_COLUMN: Int = -1
1514
internal const val DEFAULT_ROW: Int = 0
1615
internal const val DEFAULT_COLUMN: Int = 0
17-
internal val DefaultSpan: GridItemSpanScope.() -> Int = { 1 }
1816
}
1917
}

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

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,14 @@ interface BoxGridScope {
3131
fun Modifier.column(column: Int): Modifier
3232

3333
/**
34-
* Sets the row span of the cell. The default span size is 1.
34+
* Sets the row and column span of the cell. The default span size is 1.
3535
*
36-
* @param span A span calculation lambda. If the result of [span] lambda is null, it means
37-
* that this item uses default span size.
36+
* @param span A span calculation lambda. If the result is null, it means that this item uses
37+
* the default span size.
3838
*/
3939
@Stable
4040
@ExperimentalGridApi
41-
fun Modifier.rowSpan(span: ((GridItemSpanScope.() -> Int))? = null): Modifier
42-
43-
/**
44-
* Sets the column span of the cell. The default span size is 1.
45-
*
46-
* @param span A span calculation lambda. If the result of [span] lambda is null, it means
47-
* that this item uses default span size.
48-
*/
49-
@Stable
50-
@ExperimentalGridApi
51-
fun Modifier.columnSpan(span: ((GridItemSpanScope.() -> Int))? = null): Modifier
41+
fun Modifier.span(span: ((BoxGridItemSpanScope).() -> BoxGridItemSpan)? = null): Modifier
5242

5343
/**
5444
* Aligns the item to specific [Alignment] within the cell.
@@ -86,24 +76,12 @@ internal object BoxGridScopeInstance : BoxGridScope {
8676
)
8777
}
8878

89-
override fun Modifier.rowSpan(span: (GridItemSpanScope.() -> Int)?): Modifier {
90-
return this.then(
91-
BoxGridSpanElement(
92-
rowSpan = span ?: BoxGridParentData.DefaultSpan,
93-
inspectorInfo = debugInspectorInfo {
94-
name = "rowSpan"
95-
value = span
96-
}
97-
)
98-
)
99-
}
100-
101-
override fun Modifier.columnSpan(span: (GridItemSpanScope.() -> Int)?): Modifier {
79+
override fun Modifier.span(span: (BoxGridItemSpanScope.() -> BoxGridItemSpan)?): Modifier {
10280
return this.then(
10381
BoxGridSpanElement(
104-
columnSpan = span ?: BoxGridParentData.DefaultSpan,
82+
span = span,
10583
inspectorInfo = debugInspectorInfo {
106-
name = "columnSpan"
84+
name = "span"
10785
value = span
10886
}
10987
)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.cheonjaeung.compose.grid
2+
3+
import androidx.compose.runtime.Immutable
4+
import androidx.compose.runtime.Stable
5+
import androidx.compose.ui.util.packInts
6+
import androidx.compose.ui.util.unpackInt1
7+
import androidx.compose.ui.util.unpackInt2
8+
import kotlin.jvm.JvmInline
9+
10+
/**
11+
* Create a [BoxGridItemSpan] from the given [row] and [column] span size parameter..
12+
*/
13+
fun BoxGridItemSpan(row: Int, column: Int): BoxGridItemSpan {
14+
require(row > 0) { "span must be bigger than zero but rowSpan is $row" }
15+
require(column > 0) { "span must be bigger than zero but columnSpan is $column" }
16+
return BoxGridItemSpan(packedValue = packInts(row, column))
17+
}
18+
19+
/**
20+
* A value class which represents the spans of an item in a [BoxGrid].
21+
*/
22+
@Immutable
23+
@JvmInline
24+
value class BoxGridItemSpan internal constructor(private val packedValue: Long) {
25+
@Stable
26+
val rowSpan: Int
27+
get() = unpackInt1(packedValue)
28+
29+
@Stable
30+
val columnSpan: Int
31+
get() = unpackInt2(packedValue)
32+
33+
@Stable
34+
operator fun component1(): Int = rowSpan
35+
36+
@Stable
37+
operator fun component2(): Int = columnSpan
38+
39+
companion object {
40+
@Stable
41+
internal val Default = BoxGridItemSpan(row = 1, column = 1)
42+
}
43+
}
44+
45+
/**
46+
* A scope to calculate spans of items in the box grid layout.
47+
*/
48+
@GridItemScopeMarker
49+
sealed interface BoxGridItemSpanScope {
50+
/**
51+
* The maximum current row line span.
52+
*/
53+
val maxCurrentRowSpan: Int
54+
55+
/**
56+
* The maximum current column line span.
57+
*/
58+
val maxCurrentColumnSpan: Int
59+
60+
/**
61+
* The maximum row line span. It will be the number of the rows for box grid.
62+
*/
63+
val maxRowSpan: Int
64+
65+
/**
66+
* The maximum column line span. It will be the number of the columns for box grid.
67+
*/
68+
val maxColumnSpan: Int
69+
}
70+
71+
internal class BoxGridItemSpanScopeImpl(
72+
override var maxCurrentRowSpan: Int,
73+
override var maxCurrentColumnSpan: Int,
74+
override var maxRowSpan: Int,
75+
override var maxColumnSpan: Int
76+
) : BoxGridItemSpanScope

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@ import androidx.compose.ui.platform.InspectorInfo
77
import androidx.compose.ui.unit.Density
88

99
internal class BoxGridSpanElement(
10-
val rowSpan: (GridItemSpanScope.() -> Int)? = null,
11-
val columnSpan: (GridItemSpanScope.() -> Int)? = null,
10+
val span: (BoxGridItemSpanScope.() -> BoxGridItemSpan)? = null,
1211
val inspectorInfo: InspectorInfo.() -> Unit
1312
) : ModifierNodeElement<BoxGridSpanNode>() {
1413
override fun create(): BoxGridSpanNode {
15-
return BoxGridSpanNode(rowSpan, columnSpan)
14+
return BoxGridSpanNode(span)
1615
}
1716

1817
override fun update(node: BoxGridSpanNode) {
19-
node.rowSpan = rowSpan
20-
node.columnSpan = columnSpan
18+
node.span = span
2119
}
2220

2321
override fun InspectorInfo.inspectableProperties() {
@@ -28,27 +26,21 @@ internal class BoxGridSpanElement(
2826
if (this === other) return true
2927
if (other == null) return false
3028
if (other !is BoxGridSpanElement) return false
31-
return this.rowSpan == other.rowSpan && this.columnSpan == other.columnSpan
29+
return this.span == other.span
3230
}
3331

3432
override fun hashCode(): Int {
35-
var hash = rowSpan.hashCode()
36-
hash = 31 * hash + columnSpan.hashCode()
37-
return hash
33+
return span.hashCode()
3834
}
3935
}
4036

4137
internal class BoxGridSpanNode(
42-
var rowSpan: (GridItemSpanScope.() -> Int)?,
43-
var columnSpan: (GridItemSpanScope.() -> Int)?
38+
var span: (BoxGridItemSpanScope.() -> BoxGridItemSpan)?
4439
) : Modifier.Node(), ParentDataModifierNode {
4540
override fun Density.modifyParentData(parentData: Any?): Any {
4641
val p = parentData as? BoxGridParentData ?: BoxGridParentData()
47-
rowSpan?.let {
48-
p.rowSpan = it
49-
}
50-
columnSpan?.let {
51-
p.columnSpan = it
42+
span?.let {
43+
p.span = it
5244
}
5345
return p
5446
}

0 commit comments

Comments
 (0)