Skip to content

Commit

Permalink
#3 Custom Layout 구현
Browse files Browse the repository at this point in the history
- Column / Row / Grid 간단하게만 구현
  • Loading branch information
lee-ji-hoon committed Feb 27, 2024
1 parent ab759b0 commit 6e22540
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.sample.feature.compose_layout.LayoutSampleModifyColumn
import com.sample.feature.compose_layout.LayoutSampleModifyGrid
import com.sample.feature.compose_layout.LayoutSampleModifyRow
import com.sample.feature.compose_layout.LayoutSampleScreen
import com.sample.feature.window.WindowSampleActivity

Expand Down Expand Up @@ -43,10 +47,35 @@ fun PlaygroundNavigation() {
}
}

composable(route = PlaygroundNavigation.Layout.route) {
LayoutSampleScreen()
layoutSampleGraph(navController::navigate)
}
}

fun NavGraphBuilder.layoutSampleGraph(onNavigate: (route: String) -> Unit) {
composable(
route = "${PlaygroundNavigation.Layout}"
) {
LayoutSampleScreen{
onNavigate("${PlaygroundNavigation.Layout}/$it")
}
}
composable(
route = "${PlaygroundNavigation.Layout}/row"
) {
LayoutSampleModifyRow()
}

composable(
route = "${PlaygroundNavigation.Layout}/column"
) {
LayoutSampleModifyColumn()
}

composable(
route = "${PlaygroundNavigation.Layout}/grid"
) {
LayoutSampleModifyGrid()
}
}

sealed interface PlaygroundNavigation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fun PlaygroundMainScreen(
Column(
modifier = modifier.fillMaxSize()
) {
playgroundItems.forEach {
playGroundStates.forEach {
PlaygroundItem(
name = it.name,
description = it.description,
Expand All @@ -26,21 +26,29 @@ fun PlaygroundMainScreen(
}
}

private val playgroundItems = listOf(
PlaygroundItem(
private val playGroundStates = listOf(
PlayGroundState(
name = "Window",
description = "Cutout, Immersive, SystemBars에 대한 예제입니다.",
navigationRoute = PlaygroundNavigation.Window
),
PlaygroundItem(
PlayGroundState(
name = "Layout",
description = "Layout에 대한 예제입니다.",
navigationRoute = PlaygroundNavigation.Layout
navigationRoute = PlaygroundNavigation.Layout,
subItems = listOf(
PlayGroundState(
name = "Layout/",
description = "Custom Layout Row 예제",
navigationRoute = PlaygroundNavigation.Layout,
)
)
),
)

data class PlaygroundItem(
data class PlayGroundState(
val name: String,
val description: String,
val navigationRoute: PlaygroundNavigation
val navigationRoute: PlaygroundNavigation,
val subItems: List<PlayGroundState> = emptyList()
)
1 change: 1 addition & 0 deletions feature/compose-layout/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ android {
}

dependencies {
implementation(project(":base"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.sample.feature.compose_layout

import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp

@Composable
fun LayoutSampleModifyRow(
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {
Text(text = "first")
Spacer(modifier = Modifier.width(20.dp))
Text(text = "second")
Spacer(modifier = Modifier.width(20.dp))
Text(text = "third")
}
) {
Layout(
modifier = modifier
.fillMaxSize()
.background(Color.Gray),
content = content
) { measureable: List<Measurable>, constraints: Constraints ->
val placeables = measureable.map { it.measure(constraints.copy(minWidth = 0, minHeight = 0)) }

layout(width = constraints.maxWidth, height = constraints.maxHeight) {
var x = 0
placeables.forEach {
Log.d(TAG, "place x $x ")
it.placeRelative(x, y = 0)
x += it.width
}
}
}
}

@Preview(showBackground = true)
@Composable
fun LayoutSampleModifyRowPreview() {
LayoutSampleModifyRow()
}

val TAG = "TAG"
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sample.feature.compose_layout

import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints

@Composable
fun LayoutSampleModifyColumn(
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {
Text(text = "first", modifier = Modifier.background(Color.Black))
Text(text = "second", modifier = Modifier.background(Color.Blue))
Text(text = "third", modifier = Modifier.background(Color.Cyan))
}
) {
Layout(
modifier = modifier
.fillMaxSize()
.background(Color.Gray),
content = content
) { measureable: List<Measurable>, constraints: Constraints ->
val minWidthHeightZeroConstraint = constraints.copy(minWidth = 0, minHeight = 0)
val placeables = measureable.map { it.measure(minWidthHeightZeroConstraint) }

layout(width = constraints.maxWidth, height = constraints.maxHeight) {
var y = 0
placeables.forEach { placeable ->
Log.d(TAG, "y $y")
placeable.placeRelative(x = 0, y = y)
y += placeable.height
}
}
}
}

@Preview(showBackground = true)
@Composable
private fun LayoutSampleModifyColumnPreview() {
LayoutSampleModifyColumn()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.sample.feature.compose_layout

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import kotlin.random.Random

private fun getRandomColor(): Color {
val randomColorValue = Random.nextLong(from = 0xFF000000, until = 0xFFFFFFFF)
return Color(randomColorValue)
}

@Composable
fun LayoutSampleModifyGrid(
modifier: Modifier = Modifier,
columns: Int = 2,
itemPadding: PaddingValues = PaddingValues(10.dp),
content: @Composable () -> Unit = {
val sizes = listOf(150.dp, 200.dp, 300.dp, 150.dp, 100.dp, 100.dp)
val createBox: @Composable (Dp) -> Unit = { size ->
Box(
modifier = Modifier
.size(size)
.background(getRandomColor())
)
}
sizes.forEach { size ->
createBox(size)
}
}
) {
Layout(
modifier = modifier,
content = content
) { measurables: List<Measurable>, constraints: Constraints ->
val columnWidth = constraints.maxWidth / columns
val itemConstraints = constraints.copy(maxWidth = columnWidth)
val left = itemPadding.calculateLeftPadding(LayoutDirection.Ltr).roundToPx()
val right = itemPadding.calculateRightPadding(LayoutDirection.Ltr).roundToPx()
val top = itemPadding.calculateTopPadding().roundToPx()
val bottom = itemPadding.calculateBottomPadding().roundToPx()

val placeables: List<List<Placeable>> = measurables.map { measurable ->
measurable.measure(itemConstraints)
}.chunked(columns)

val gridHeight = placeables.sumOf { gridPlaceables -> gridPlaceables.maxOf { it.height } }

layout(constraints.maxWidth, gridHeight) {
var y = top
placeables.forEach { currentColumnPlaceables ->
val currentColumnMaxHeight = currentColumnPlaceables.maxOf { it.height }
var x = left
currentColumnPlaceables.forEach { placeable ->
placeable.place(x, y)
x += placeable.width + right
}
y += currentColumnMaxHeight + bottom
}
}
}
}

@Preview
@Composable
private fun LayoutSampleModifyGridPreview() {
LayoutSampleModifyGrid()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,33 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.sample.base.PlaygroundItem

@Composable
fun LayoutSampleScreen(
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
onNavigate: (route: String) -> Unit
) {
Column(modifier.fillMaxSize()) {
PlaygroundItem(
name = "Row",
description = "Layout으로 직접 만든 Row입니다.",
destinationRoute = "row",
onNavigate = onNavigate::invoke
)

PlaygroundItem(
name = "Column",
description = "Layout으로 직접 만든 Column입니다.",
destinationRoute = "column",
onNavigate = onNavigate::invoke
)

PlaygroundItem(
name = "Grid",
description = "Layout으로 직접 만든 Column입니다.",
destinationRoute = "grid",
onNavigate = onNavigate::invoke
)
}
}

0 comments on commit 6e22540

Please sign in to comment.