Skip to content

Commit c17b318

Browse files
authored
Merge pull request #27 from sproctor/feat/android-scrollbar-sample
Feat/android scrollbar sample
2 parents 8e39544 + c3e6609 commit c17b318

9 files changed

Lines changed: 87 additions & 142 deletions

File tree

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

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ class DataTableMeasuredRow(
4747
space = IntSize(columnWidth, height),
4848
layoutDirection = layoutDirection
4949
)
50-
placeableOffsets[index * 2] =
51-
x + alignmentOffset.x
50+
placeableOffsets[index * 2] = x + alignmentOffset.x
5251
placeableOffsets[index * 2 + 1] = offset.y + alignmentOffset.y
5352
x += columnWidth
5453
}
@@ -67,45 +66,48 @@ class DataTableMeasuredRow(
6766
with(placementBlock) {
6867
with(subcomposeScope) {
6968
subcompose(key, background).map {
70-
val placeable = it.measure(
69+
it.measure(
7170
Constraints(
7271
minHeight = height,
7372
maxHeight = height,
7473
minWidth = tableWidth,
7574
maxWidth = tableWidth,
7675
)
7776
)
78-
// .place(0, backgroundOffset)
79-
// if (upperBound >= backgroundOffset && lowerBound < backgroundOffset) {
80-
// placeable.place(0, backgroundOffset)
81-
// } else {
82-
placeable.placeWithLayer(0, backgroundOffset) {
83-
shape = object : Shape {
84-
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
85-
val sizeRect = size.toRect()
86-
return Outline.Rectangle(
87-
sizeRect.copy(
88-
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - backgroundOffset),
89-
bottom = minOf(sizeRect.bottom, sizeRect.bottom - backgroundOffset - height + lowerBound.toFloat()),
90-
)
91-
)
92-
}
93-
}
94-
clip = true
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
9591
// }
96-
}
9792
}
9893
}
9994
placeables.forEachIndexed { index, placeable ->
10095
val offset = getOffset(index)
10196
placeable?.placeWithLayer(offset) {
10297
shape = object : Shape {
103-
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
98+
override fun createOutline(
99+
size: Size,
100+
layoutDirection: LayoutDirection,
101+
density: Density
102+
): Outline {
104103
val sizeRect = size.toRect()
105104
return Outline.Rectangle(
106105
sizeRect.copy(
107106
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - offset.y),
108-
bottom = minOf(sizeRect.bottom, sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()),
107+
bottom = minOf(
108+
sizeRect.bottom,
109+
sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()
110+
),
109111
)
110112
)
111113
}
@@ -157,20 +159,28 @@ class DataTableMeasuredSimple(
157159
}
158160
}
159161
placeables.forEach { placeable ->
160-
placeable.placeWithLayer(offset) {
161-
shape = object : Shape {
162-
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
163-
val sizeRect = size.toRect()
164-
return Outline.Rectangle(
165-
sizeRect.copy(
166-
top = maxOf(sizeRect.top, sizeRect.top + upperBound.toFloat() - offset.y),
167-
bottom = minOf(sizeRect.bottom, sizeRect.bottom - offset.y - placeable.height.toFloat() + lowerBound.toFloat()),
168-
)
169-
)
170-
}
171-
}
172-
clip = true
173-
}
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+
// }
174184
}
175185
}
176186
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ fun BasicPaginatedDataTable(
4444
) {
4545
val start = state.pageIndex * state.pageSize
4646
val scope = PaginatedRowScope(start, start + state.pageSize, this)
47-
with(scope) {
48-
content()
49-
}
47+
content(scope)
5048
if (state.count != scope.index) {
5149
state.count = scope.index
5250
}

demo-common/build.gradle.kts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,9 @@ kotlin {
1111
dependencies {
1212
implementation(project(":data-table-material3"))
1313
implementation(compose.material3)
14+
implementation(libs.fastscroller.m3)
1415
}
1516
}
16-
17-
val skikoMain by creating {
18-
dependsOn(commonMain)
19-
}
20-
21-
val jvmMain by getting {
22-
dependsOn(skikoMain)
23-
}
24-
25-
val jsMain by getting {
26-
dependsOn(skikoMain)
27-
}
2817
}
2918
}
3019

demo-common/src/androidMain/kotlin/com/seanproctor/datatable/demo/Scrollbar.android.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

demo-common/src/commonMain/kotlin/com/seanproctor/datatable/demo/App.kt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ import com.seanproctor.datatable.material3.DataTable
3131
import com.seanproctor.datatable.material3.LazyPaginatedDataTable
3232
import com.seanproctor.datatable.material3.PaginatedDataTable
3333
import com.seanproctor.datatable.paging.rememberPaginatedDataTableState
34+
import io.github.oikvpqya.compose.fastscroller.HorizontalScrollbar
35+
import io.github.oikvpqya.compose.fastscroller.VerticalScrollbar
36+
import io.github.oikvpqya.compose.fastscroller.material3.defaultMaterialScrollbarStyle
3437
import kotlin.math.min
3538

3639
@OptIn(ExperimentalMaterial3Api::class)
@@ -98,8 +101,6 @@ fun App(onRowClick: (Int) -> Unit) {
98101
sortColumnIndex = sortColumnIndex,
99102
sortAscending = sortAscending,
100103
modifier = Modifier.fillMaxWidth().padding(16.dp),
101-
// headerBackgroundColor = MaterialTheme.colorScheme.surface,
102-
// footerBackgroundColor = MaterialTheme.colorScheme.surface,
103104
footer = {
104105
Box {
105106
Text(
@@ -111,7 +112,6 @@ fun App(onRowClick: (Int) -> Unit) {
111112
)
112113
}
113114
}
114-
// logger = { println(it) }
115115
) {
116116
generateTable(
117117
colorEven = colorEven,
@@ -120,17 +120,15 @@ fun App(onRowClick: (Int) -> Unit) {
120120
onRowClick = onRowClick,
121121
)
122122
}
123-
LaunchedEffect(scrollState.horizontalScrollState.viewportSize) {
124-
println("viewport: ${scrollState.horizontalScrollState.viewportSize}")
125-
println("total size: ${scrollState.horizontalScrollState.totalSize}")
126-
}
127123
VerticalScrollbar(
128-
scrollState.verticalScrollState,
129-
Modifier.fillMaxHeight().align(Alignment.CenterEnd)
124+
adapter = rememberScrollbarAdapter(scrollState.verticalScrollState),
125+
style = defaultMaterialScrollbarStyle(),
126+
modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd),
130127
)
131128
HorizontalScrollbar(
132-
scrollState.horizontalScrollState,
133-
Modifier.fillMaxWidth().align(Alignment.BottomCenter)
129+
adapter = rememberScrollbarAdapter(scrollState.horizontalScrollState),
130+
style = defaultMaterialScrollbarStyle(),
131+
modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)
134132
)
135133
}
136134
} else if (selectedIndex == 1) {
@@ -188,7 +186,7 @@ fun DataTableScope.generateTable(
188186
) {
189187
data.forEachIndexed { index, rowData ->
190188
row {
191-
backgroundColor = if (index % 2 == 0) colorEven else colorOdd
189+
// backgroundColor = if (index % 2 == 0) colorEven else colorOdd
192190
onClick = { onRowClick(index) }
193191
cell { }
194192
cell {
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
11
package com.seanproctor.datatable.demo
22

33
import androidx.compose.runtime.Composable
4-
import androidx.compose.ui.Modifier
4+
import androidx.compose.runtime.remember
55
import com.seanproctor.datatable.DataTableScrollState
6+
import io.github.oikvpqya.compose.fastscroller.ScrollbarAdapter
7+
import kotlin.math.roundToInt
68

79
@Composable
8-
expect fun VerticalScrollbar(scrollState: DataTableScrollState, modifier: Modifier)
10+
fun rememberScrollbarAdapter(scrollState: DataTableScrollState): ScrollbarAdapter {
11+
return remember(scrollState) { DataTableScrollbarAdapter(scrollState) }
12+
}
913

10-
@Composable
11-
expect fun HorizontalScrollbar(scrollState: DataTableScrollState, modifier: Modifier)
14+
private class DataTableScrollbarAdapter(
15+
private val scrollState: DataTableScrollState
16+
) : ScrollbarAdapter {
17+
override val scrollOffset: Double get() = scrollState.offset.toDouble()
18+
19+
override suspend fun scrollTo(scrollOffset: Double) {
20+
scrollState.scrollTo(scrollOffset.roundToInt())
21+
}
22+
23+
override val contentSize: Double
24+
// This isn't strictly correct, as the actual content can be smaller
25+
// than the viewport when scrollState.maxValue is 0, but the scrollbar
26+
// doesn't really care as long as contentSize <= viewportSize; it's
27+
// just not showing itself
28+
get() = scrollState.totalSize.toDouble()
29+
30+
override val viewportSize: Double
31+
get() = scrollState.viewportSize.toDouble()
32+
}

demo-common/src/iosMain/kotlin/com/seanproctor/datatable/demo/Scrollbar.ios.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

demo-common/src/skikoMain/kotlin/com/seanproctor/datatable/demo/Scrollbar.jvm.kt

Lines changed: 0 additions & 51 deletions
This file was deleted.

gradle/libs.versions.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@ datatable-android-application = { id = "datatable.android.application" }
1818

1919
[versions]
2020

21-
activityCompose = "1.10.0"
21+
activityCompose = "1.10.1"
2222
androidGradlePlugin = "8.7.3"
2323
androidTools = "31.7.3"
2424
androidxLintGradle = "1.0.0-alpha03"
2525
compose = "1.7.3"
26+
fastscroller = "0.3.0"
2627
kotlin = "2.1.10"
2728
truth = "1.4.4"
2829
vanniktech = "0.30.0"
2930

3031
[libraries]
3132

3233
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
34+
fastscroller-m3 = { module = "io.github.oikvpqya.compose.fastscroller:fastscroller-material3", version.ref = "fastscroller" }
3335
truth = { group = "com.google.truth", name = "truth", version.ref = "truth" }
3436

3537
# Dependencies of the included build-logic

0 commit comments

Comments
 (0)