-
Notifications
You must be signed in to change notification settings - Fork 1
Scaffold 구현 #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Scaffold 구현 #15
Changes from all commits
295cf7d
16929e0
ef2420b
010ff2a
18963f8
509104a
920aa0e
50cbb63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| package com.yourssu.handy.demo | ||
|
|
||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.fillMaxSize | ||
| import androidx.compose.foundation.layout.fillMaxWidth | ||
| import androidx.compose.foundation.layout.height | ||
| 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.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import com.yourssu.handy.compose.HandyTheme | ||
| import com.yourssu.handy.compose.Scaffold | ||
|
|
||
| @Composable | ||
| @Preview | ||
| fun ScaffoldAllExistPreview() { | ||
| HandyTheme { | ||
| Scaffold( | ||
| topBar = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Blue) | ||
| ) | ||
| }, | ||
| bottomBar = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Green) | ||
| ) | ||
| }, | ||
| snackbarHost = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Red) | ||
| ) | ||
| }, | ||
| floatingActionButton = { | ||
| Box( | ||
| modifier = Modifier | ||
| .size(56.dp) | ||
| .background(Color.Yellow) | ||
| ) | ||
| }, | ||
| content = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .background(Color.Gray) | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| @Preview | ||
| fun ScaffoldNonExistFabPreview() { | ||
| HandyTheme { | ||
| Scaffold( | ||
| topBar = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Blue) | ||
| ) | ||
| }, | ||
| bottomBar = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Green) | ||
| ) | ||
| }, | ||
| snackbarHost = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Red) | ||
| ) | ||
| }, | ||
| content = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .background(Color.Gray) | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| @Preview | ||
| fun ScaffoldNonExistBottomBarPreview() { | ||
| HandyTheme { | ||
| Scaffold( | ||
| topBar = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Blue) | ||
| ) | ||
| }, | ||
| snackbarHost = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(56.dp) | ||
| .background(Color.Red) | ||
| ) | ||
| }, | ||
| floatingActionButton = { | ||
| Box( | ||
| modifier = Modifier | ||
| .size(56.dp) | ||
| .background(Color.Yellow) | ||
| ) | ||
| }, | ||
| content = { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .background(Color.Gray) | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| package com.yourssu.handy.compose | ||
|
|
||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.PaddingValues | ||
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.layout.SubcomposeLayout | ||
| import androidx.compose.ui.platform.LocalDensity | ||
| import androidx.compose.ui.semantics.isTraversalGroup | ||
| import androidx.compose.ui.semantics.semantics | ||
| import androidx.compose.ui.semantics.traversalIndex | ||
| import androidx.compose.ui.unit.dp | ||
| import com.yourssu.handy.compose.ScaffoldSpacingValues.FabBottomSpacing | ||
| import com.yourssu.handy.compose.ScaffoldSpacingValues.FabEndSpacing | ||
| import com.yourssu.handy.compose.ScaffoldSpacingValues.SnackBarBottomSpacing | ||
| import com.yourssu.handy.compose.foundation.LocalContentColor | ||
|
|
||
| /** | ||
| * layout을 구성하기 위한 Scaffold입니다. | ||
| * | ||
| * @param modifier : Modifier | ||
| * @param topBar : 상단 바 | ||
| * @param snackbarHost : Snackbar | ||
| * @param floatingActionButton : Floating Action Button | ||
| * @param bottomBar : 하단 네비게이션 바 | ||
| * @param containerColor : Scaffold의 배경색 | ||
| * @param contentColor : Scaffold의 content 색상 | ||
| * @param content : Scaffold의 content | ||
| */ | ||
| @Composable | ||
| fun Scaffold( | ||
| modifier: Modifier = Modifier, | ||
| topBar: @Composable () -> Unit = {}, | ||
| snackbarHost: @Composable () -> Unit = {}, | ||
| floatingActionButton: @Composable () -> Unit = {}, | ||
| bottomBar: @Composable () -> Unit = {}, | ||
| containerColor: Color = Color.Unspecified, | ||
| contentColor: Color = LocalContentColor.current, | ||
| content: @Composable (PaddingValues) -> Unit | ||
| ) { | ||
| Surface( | ||
| modifier = modifier, | ||
| backgroundColor = containerColor, | ||
| contentColor = contentColor | ||
| ) { | ||
| ScaffoldLayout( | ||
| topBar = topBar, | ||
| content = content, | ||
| snackbar = snackbarHost, | ||
| fab = floatingActionButton, | ||
| bottomBar = bottomBar | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * ScaffoldLayout을 구성하는 함수입니다. | ||
| * @param topBar : 상단 바 | ||
| * @param content : Scaffold의 content | ||
| * @param snackbar : Snackbar | ||
| * @param fab : Floating Action Button | ||
| * @param bottomBar : 하단 네비게이션 바 | ||
| */ | ||
| @Composable | ||
| private fun ScaffoldLayout( | ||
| topBar: @Composable () -> Unit, | ||
| content: @Composable (PaddingValues) -> Unit, | ||
| snackbar: @Composable () -> Unit, | ||
| fab: @Composable () -> Unit, | ||
| bottomBar: @Composable () -> Unit | ||
| ) { | ||
| val snackBarPxValue = LocalDensity.current.run { SnackBarBottomSpacing.toPx() }.toInt() | ||
| val fabEndMarginPxValue = LocalDensity.current.run { FabEndSpacing.toPx() }.toInt() | ||
| val fabBottomMarginPxValue = LocalDensity.current.run { FabBottomSpacing.toPx() }.toInt() | ||
|
|
||
| SubcomposeLayout( | ||
| modifier = Modifier.semantics { isTraversalGroup = true } | ||
| ) { constraints -> | ||
| val layoutWidth = constraints.maxWidth | ||
| val layoutHeight = constraints.maxHeight | ||
|
|
||
| val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0) | ||
|
|
||
| val topBarPlaceable = subcompose(ScaffoldLayoutContent.TopBar) { | ||
cometj03 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Box( | ||
| modifier = Modifier.semantics { | ||
| isTraversalGroup = true | ||
| traversalIndex = 0f | ||
| } | ||
| ) { | ||
| topBar() | ||
| } | ||
| }.first().measure(looseConstraints) | ||
|
|
||
| val snackBarPlaceable = subcompose(ScaffoldLayoutContent.Snackbar) { | ||
| Box(modifier = Modifier | ||
| .padding() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거 |
||
| .semantics { | ||
| isTraversalGroup = true | ||
| traversalIndex = 4f | ||
| } | ||
| ) { | ||
| snackbar() | ||
| } | ||
| }.first().measure(looseConstraints) | ||
|
|
||
| val fabPlaceable = subcompose(ScaffoldLayoutContent.Fab) { | ||
| Box(modifier = Modifier.semantics { | ||
| isTraversalGroup = true | ||
| traversalIndex = 3f | ||
| }) { | ||
| fab() | ||
| } | ||
| }.first().measure(looseConstraints) | ||
|
|
||
| val bottomBarPlaceable = subcompose(ScaffoldLayoutContent.BottomBar) { | ||
| Box(modifier = Modifier.semantics { | ||
| isTraversalGroup = true | ||
| traversalIndex = 1f | ||
| }) { | ||
| bottomBar() | ||
| } | ||
| }.first().measure(looseConstraints) | ||
|
|
||
| val mainContentPlaceable = subcompose(ScaffoldLayoutContent.MainContent) { | ||
| Box( | ||
| modifier = Modifier.semantics { | ||
| isTraversalGroup = true | ||
| traversalIndex = 2f | ||
| } | ||
| ) { | ||
| content( | ||
| PaddingValues( | ||
| top = with(LocalDensity.current) { topBarPlaceable.height.toDp() }, | ||
| bottom = with(LocalDensity.current) { bottomBarPlaceable.height.toDp() } | ||
| ) | ||
| ) | ||
| } | ||
| }.first().measure(looseConstraints) | ||
|
|
||
| val bottomBarVerticalOffset = layoutHeight - bottomBarPlaceable.height | ||
|
|
||
| val snackBarVerticalOffset = bottomBarVerticalOffset - snackBarPlaceable.height - snackBarPxValue | ||
|
|
||
| val fabVerticalOffset = bottomBarVerticalOffset - fabPlaceable.height - fabBottomMarginPxValue | ||
| val fabHorizontalOffset = layoutWidth - fabPlaceable.width - fabEndMarginPxValue | ||
|
|
||
| layout(layoutWidth, layoutHeight) { | ||
| topBarPlaceable.placeRelative(0, 0) | ||
| mainContentPlaceable.placeRelative(0, topBarPlaceable.height) | ||
| snackBarPlaceable.placeRelative(0, snackBarVerticalOffset) | ||
| fabPlaceable.placeRelative(fabHorizontalOffset, fabVerticalOffset) | ||
| bottomBarPlaceable.placeRelative(0, bottomBarVerticalOffset) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| object ScaffoldSpacingValues { | ||
| val FabBottomSpacing = 32.dp | ||
| val FabEndSpacing = 16.dp | ||
| val SnackBarBottomSpacing = 16.dp | ||
| } | ||
|
Comment on lines
+160
to
+164
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| private enum class ScaffoldLayoutContent { | ||
| TopBar, | ||
| MainContent, | ||
| Snackbar, | ||
| Fab, | ||
| BottomBar | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.