Skip to content

Commit

Permalink
♻️ refactored the ColumnThatResizesFirstItem so that it is more flexi…
Browse files Browse the repository at this point in the history
…ble and preserved the animation
  • Loading branch information
CXwudi committed Jan 1, 2024
1 parent bc6d815 commit 24a3ec7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,43 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.SubcomposeLayout


/**
* Column with specialized spacing for the first item using [SubcomposeLayout]
* A two-item column that resizes its first item to make sure the second item is always visible.
*
* @param modifier The modifier to be applied to the [SubcomposeLayout]
* @param resizibleFirstContent The composable function that draws the first item
* @param fixedSizeSecondContent The composable function that draws the second item
*/
@Composable
fun ColumnThatResizesFirstItem(
modifier: Modifier = Modifier,
spacing: Int = 0,
content: @Composable () -> Unit
resizibleFirstContent: @Composable () -> Unit,
fixedSizeSecondContent: @Composable () -> Unit
) {
// see https://foso.github.io/Jetpack-Compose-Playground/ui/layout/subcomposelayout/
// and https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/package-summary#SubcomposeLayout(androidx.compose.ui.Modifier,kotlin.Function2)
SubcomposeLayout(modifier = modifier) { constraints ->
val placeables = subcompose(ColumnItem.Main, content).map {
val fixedSizePlacebles = subcompose(Phase.One, fixedSizeSecondContent).map {
it.measure(constraints.copy(minHeight = 0, minWidth = 0))
}
val firstContentMaxHeight = fixedSizePlacebles.maxOfOrNull { it.height } ?: 0
val remainingHeight: Int = constraints.maxHeight - firstContentMaxHeight

val remainingHeight: Int = constraints.maxHeight - placeables.drop(1).fold(0) { acc, placeable ->
acc + placeable.height
} - spacing * (placeables.size - 1)

val restMeasurables = subcompose(ColumnItem.Rest, content)
val firstPlaceable =
restMeasurables.first().measure(constraints.copy(minHeight = remainingHeight, maxHeight = remainingHeight))
val restPlaceables = restMeasurables.drop(1).map {
it.measure(constraints.copy(minHeight = 0, minWidth = 0))
val resiziblePlacebles = subcompose(Phase.Two, resizibleFirstContent).map {
it.measure(constraints.copy(minHeight = 0, maxHeight = remainingHeight))
}

val resizedPlaceables = listOf(firstPlaceable) + restPlaceables
val yPosition = resiziblePlacebles.maxOfOrNull { it.height } ?: 0

layout(constraints.maxWidth, constraints.maxHeight) {
var yPosition = 0
resizedPlaceables.forEach { placeable ->
resiziblePlacebles.forEach { placeable ->
placeable.placeRelative(0, 0)
}
fixedSizePlacebles.forEach { placeable ->
placeable.placeRelative(0, yPosition)
yPosition += placeable.measuredHeight + spacing
}
}
}
}

enum class ColumnItem {
Main, Rest
}
private enum class Phase {
One, Two
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package mikufan.cx.songfinder.ui.component.main

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -37,19 +36,32 @@ fun MainScreen(


@Composable
fun RealMainScreen(isAllFinished: State<Boolean>) = ColumnWithSpacing(
horizontalAlignment = Alignment.Start
) {
fun RealMainScreen(isAllFinished: State<Boolean>) = ColumnWithSpacing {
ProgressBar()
Divider()
RestOfPart(isAllFinished.value, { FinishMessagePanel() }, {
SearchBar()
RegexMatchOption()
ColumnThatResizesFirstItem(Modifier.fillMaxSize(), spacing = MaterialTheme.spacing.spacing.value.toInt()) {
ResultPanel()
Divider()
ResultOverridingPanel()
}
ColumnThatResizesFirstItem(
modifier = Modifier.fillMaxSize(),
resizibleFirstContent = {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
ResultPanel()
}
},
fixedSizeSecondContent = {
Column(
modifier = Modifier.padding(top = MaterialTheme.spacing.padding),
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.spacing),
) {
Divider()
ResultOverridingPanel()
}
}
)
})
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package mikufan.cx.songfinder.ui.test

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Divider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import mikufan.cx.songfinder.ui.common.ColumnThatResizesFirstItem
import mikufan.cx.songfinder.ui.theme.MyAppTheme
Expand All @@ -20,21 +22,36 @@ fun main(args: Array<String>) = singleWindowApplication {
@Composable
fun DrawColumn() {
Column {
ColumnThatResizesFirstItem(modifier = Modifier.fillMaxSize(), spacing = 10) {
SampleLazyColumn()
Divider()
Text("Should see this text")
}
// ColumnThatResizesFirstItem(modifier = Modifier.fillMaxSize(), spacing = 10) {
// SampleLazyColumn()
// Divider()
// Text("Should see this text")
// }
ColumnThatResizesFirstItem(
resizibleFirstContent = { SampleLazyColumn() },
fixedSizeSecondContent = { SampleButtomBar() }
)
}

}

@Composable
fun SampleLazyColumn() {
private fun SampleLazyColumn() {
// draw 100 numbers
LazyColumn {
LazyColumn() {
items(35) {
Text(it.toString())
}
}
}
}

@Composable
private fun SampleButtomBar() {
Column(
modifier = Modifier.padding(vertical = 5.dp),
verticalArrangement = Arrangement.spacedBy(5.dp)
) {
Divider()
Text("Should see this text")
}
}

0 comments on commit 24a3ec7

Please sign in to comment.