Skip to content

Commit ca087c0

Browse files
authored
Merge pull request #28 from sproctor/fix/scroll-remnants
don't place unpositioned elements
2 parents c17b318 + 012b04e commit ca087c0

2 files changed

Lines changed: 74 additions & 58 deletions

File tree

data-table/src/commonMain/kotlin/com/seanproctor/datatable/BasicDataTable.kt

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,11 @@ fun BasicDataTable(
237237
}
238238
} else {
239239
val rowData = tableScope.tableRows[row - 1]
240-
Box(Modifier
241-
.background(rowData.backgroundColor)
242-
.fillMaxSize()
243-
.then(if (rowData.onClick != null) Modifier.clickable { rowData.onClick?.invoke() } else Modifier)
240+
Box(
241+
Modifier
242+
.background(rowData.backgroundColor)
243+
.fillMaxSize()
244+
.then(if (rowData.onClick != null) Modifier.clickable { rowData.onClick?.invoke() } else Modifier)
244245
) {
245246
if (row < rowCount - 1) {
246247
Box(Modifier.align(Alignment.BottomStart)) {
@@ -304,29 +305,29 @@ fun BasicDataTable(
304305
var headerOffset = 0
305306
var footerOffset = state.verticalScrollState.viewportSize
306307
val offsetX = -state.horizontalScrollState.offset
308+
// Place headers and footers first to get their measurements
307309
measuredRows.forEach { row ->
308310
if (row.isHeader) {
309311
row.position(offsetX, headerOffset)
310312
headerOffset += row.height
313+
row.place(this@SubcomposeLayout, this, 0, state.verticalScrollState.viewportSize)
311314
} else if (row.isFooter) {
312315
footerOffset -= row.height
313316
row.position(offsetX, footerOffset)
314-
} else {
317+
row.place(this@SubcomposeLayout, this, 0, state.verticalScrollState.viewportSize)
318+
}
319+
}
320+
// Place headers and footers last
321+
measuredRows.forEach { row ->
322+
if (!row.isHeader && !row.isFooter) {
315323
val y = offset - state.verticalScrollState.offset
316324
offset += row.height
317325
if (y > -row.height && y < state.verticalScrollState.viewportSize) {
318326
row.position(offsetX, y + headerOffset)
327+
row.place(this@SubcomposeLayout, this, upperBound = headerOffset, lowerBound = footerOffset)
319328
}
320329
}
321330
}
322-
// Place headers and footers last
323-
measuredRows.forEach { row ->
324-
if (row.isHeader || row.isFooter) {
325-
row.place(this@SubcomposeLayout, this, 0, state.verticalScrollState.viewportSize)
326-
} else {
327-
row.place(this@SubcomposeLayout, this, upperBound = headerOffset, lowerBound = footerOffset)
328-
}
329-
}
330331
}
331332
}
332333
}

data-table/src/commonMain/kotlin/com/seanproctor/datatable/DataTableMeasuredRow.kt

Lines changed: 60 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ import androidx.compose.ui.graphics.Outline
88
import androidx.compose.ui.graphics.Shape
99
import androidx.compose.ui.layout.Placeable
1010
import androidx.compose.ui.layout.SubcomposeMeasureScope
11-
import androidx.compose.ui.unit.Constraints
12-
import androidx.compose.ui.unit.Density
13-
import androidx.compose.ui.unit.IntOffset
14-
import androidx.compose.ui.unit.IntSize
15-
import androidx.compose.ui.unit.LayoutDirection
11+
import androidx.compose.ui.unit.*
1612

1713
class DataTableMeasuredRow(
1814
val placeables: Array<Placeable?>,
@@ -59,7 +55,8 @@ class DataTableMeasuredRow(
5955
}
6056

6157
override fun place(
62-
subcomposeScope: SubcomposeMeasureScope, placementBlock: Placeable.PlacementScope,
58+
subcomposeScope: SubcomposeMeasureScope,
59+
placementBlock: Placeable.PlacementScope,
6360
upperBound: Int,
6461
lowerBound: Int,
6562
) {
@@ -74,21 +71,20 @@ class DataTableMeasuredRow(
7471
maxWidth = tableWidth,
7572
)
7673
)
77-
.place(0, backgroundOffset)
78-
// .placeWithLayer(0, backgroundOffset) {
79-
// shape = object : Shape {
80-
// override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
81-
// val sizeRect = size.toRect()
82-
// return Outline.Rectangle(
83-
// sizeRect.copy(
84-
// top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - backgroundOffset),
85-
// bottom = minOf(sizeRect.bottom, sizeRect.bottom - backgroundOffset - height + lowerBound.toFloat()),
86-
// )
87-
// )
88-
// }
89-
// }
90-
// clip = true
91-
// }
74+
.placeWithLayer(0, backgroundOffset) {
75+
shape = object : Shape {
76+
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
77+
val sizeRect = size.toRect()
78+
return Outline.Rectangle(
79+
sizeRect.copy(
80+
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - backgroundOffset),
81+
bottom = minOf(sizeRect.bottom, sizeRect.bottom - backgroundOffset - height + lowerBound.toFloat()),
82+
)
83+
)
84+
}
85+
}
86+
clip = true
87+
}
9288
}
9389
}
9490
placeables.forEachIndexed { index, placeable ->
@@ -147,40 +143,59 @@ class DataTableMeasuredSimple(
147143
with(placementBlock) {
148144
with(subcomposeScope) {
149145
subcompose(key, background).map {
150-
it.measure(
146+
val placeable = it.measure(
151147
Constraints(
152148
minHeight = height,
153149
maxHeight = height,
154150
minWidth = tableWidth,
155151
maxWidth = tableWidth,
156152
)
157153
)
158-
.place(offset)
154+
placeable.placeWithLayer(offset) {
155+
shape = object : Shape {
156+
override fun createOutline(
157+
size: Size,
158+
layoutDirection: LayoutDirection,
159+
density: Density
160+
): Outline {
161+
val sizeRect = size.toRect()
162+
return Outline.Rectangle(
163+
sizeRect.copy(
164+
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - offset.y),
165+
bottom = minOf(
166+
sizeRect.bottom,
167+
sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()
168+
),
169+
)
170+
)
171+
}
172+
}
173+
clip = true
174+
}
159175
}
160176
}
161177
placeables.forEach { placeable ->
162-
placeable.place(offset)
163-
// placeable.placeWithLayer(offset) {
164-
// shape = object : Shape {
165-
// override fun createOutline(
166-
// size: Size,
167-
// layoutDirection: LayoutDirection,
168-
// density: Density
169-
// ): Outline {
170-
// val sizeRect = size.toRect()
171-
// return Outline.Rectangle(
172-
// sizeRect.copy(
173-
// top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - offset.y),
174-
// bottom = minOf(
175-
// sizeRect.bottom,
176-
// sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()
177-
// ),
178-
// )
179-
// )
180-
// }
181-
// }
182-
// clip = true
183-
// }
178+
placeable.placeWithLayer(offset) {
179+
shape = object : Shape {
180+
override fun createOutline(
181+
size: Size,
182+
layoutDirection: LayoutDirection,
183+
density: Density
184+
): Outline {
185+
val sizeRect = size.toRect()
186+
return Outline.Rectangle(
187+
sizeRect.copy(
188+
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - offset.y),
189+
bottom = minOf(
190+
sizeRect.bottom,
191+
sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()
192+
),
193+
)
194+
)
195+
}
196+
}
197+
clip = true
198+
}
184199
}
185200
}
186201
}

0 commit comments

Comments
 (0)