|
| 1 | +package com.yourssu.handy.compose |
| 2 | + |
| 3 | +import androidx.compose.foundation.background |
| 4 | +import androidx.compose.foundation.clickable |
| 5 | +import androidx.compose.foundation.layout.Arrangement |
| 6 | +import androidx.compose.foundation.layout.Box |
| 7 | +import androidx.compose.foundation.layout.Row |
| 8 | +import androidx.compose.foundation.layout.RowScope |
| 9 | +import androidx.compose.foundation.layout.Spacer |
| 10 | +import androidx.compose.foundation.layout.fillMaxHeight |
| 11 | +import androidx.compose.foundation.layout.fillMaxWidth |
| 12 | +import androidx.compose.foundation.layout.height |
| 13 | +import androidx.compose.foundation.layout.padding |
| 14 | +import androidx.compose.runtime.Composable |
| 15 | +import androidx.compose.ui.Alignment |
| 16 | +import androidx.compose.ui.Modifier |
| 17 | +import androidx.compose.ui.graphics.vector.ImageVector |
| 18 | +import androidx.compose.ui.text.style.TextAlign |
| 19 | +import androidx.compose.ui.unit.dp |
| 20 | +import com.yourssu.handy.compose.TopBarDefaults.topBarActionsInsidePadding |
| 21 | +import com.yourssu.handy.compose.TopBarDefaults.topBarHeight |
| 22 | +import com.yourssu.handy.compose.TopBarDefaults.topBarHorizontalPadding |
| 23 | +import com.yourssu.handy.compose.TopBarDefaults.topBarIconPadding |
| 24 | +import com.yourssu.handy.compose.foundation.HandyTypography |
| 25 | + |
| 26 | + |
| 27 | +/** |
| 28 | + * Center-Aligned Top App Bar |
| 29 | + * |
| 30 | + * 타이틀이 중앙에 위치한 탑앱바입니다. 좌측에 메뉴 아이콘 및 뒤로 가기 아이콘이 요구될 경우 사용합니다. |
| 31 | + * 아이콘으로 기능을 명확하게 표현하지 못하거나 확실하게 기능을 설명하고 싶을 때 아이콘 대신 Text를 사용할 수 있습니다. |
| 32 | + * 이때, 텍스트의 사용은 한 개까지만 가능하며, 텍스트가 공백 포함 5자일 경우 우측에 아이콘을 같이 쓸 수 없습니다. |
| 33 | + * |
| 34 | + * |
| 35 | + * @param title headline or Logo 최대 9자(공백 포함) |
| 36 | + * @param navIcon 왼쪽 아이콘 |
| 37 | + * @param actions 오른쪽 아이콘 or 텍스트 (아이콘은 임의로 변경할 수 있으며 Center-aligned의 우측엔 최대 2개의 아이콘 버튼) |
| 38 | + **/ |
| 39 | +@Composable |
| 40 | +fun CenterAlignedTopAppBar( |
| 41 | + title: String, |
| 42 | + navIcon: ImageVector, |
| 43 | + onNavIconClick: () -> Unit, |
| 44 | + modifier: Modifier = Modifier, |
| 45 | + actions: @Composable (RowScope.() -> Unit)? = null |
| 46 | +) { |
| 47 | + Box( |
| 48 | + modifier = modifier |
| 49 | + .fillMaxWidth() |
| 50 | + .background(color = HandyTheme.colors.bgBasicDefault) |
| 51 | + .height(topBarHeight) //Top App Bar의 높이값을 임의로 변경하지 않습니다. |
| 52 | + .padding(horizontal = topBarHorizontalPadding), |
| 53 | + contentAlignment = Alignment.Center |
| 54 | + ) { |
| 55 | + |
| 56 | + // CenterAligned 일 때는 좌측 아이콘이 항상 있음. |
| 57 | + Box( |
| 58 | + modifier = Modifier |
| 59 | + .align(Alignment.CenterStart) |
| 60 | + ) { |
| 61 | + Icon( |
| 62 | + imageVector = navIcon, |
| 63 | + modifier = Modifier |
| 64 | + .clickable { onNavIconClick() } |
| 65 | + .padding(topBarIconPadding) // 터치영역을 8dp만큼 확장 |
| 66 | + ) |
| 67 | + } |
| 68 | + |
| 69 | + Text( |
| 70 | + text = title, |
| 71 | + color = HandyTheme.colors.textBasicPrimary, |
| 72 | + style = HandyTypography.T2Sb18, |
| 73 | + textAlign = TextAlign.Center, |
| 74 | + ) |
| 75 | + |
| 76 | + actions?.let { |
| 77 | + Row( |
| 78 | + verticalAlignment = Alignment.CenterVertically, |
| 79 | + horizontalArrangement = Arrangement.spacedBy(topBarActionsInsidePadding), // 요소 사이에 24dp 간격 추가 |
| 80 | + modifier = Modifier.fillMaxHeight() |
| 81 | + ) { |
| 82 | + Spacer(modifier = Modifier.weight(1f)) |
| 83 | + actions() |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | + |
| 90 | +/** |
| 91 | + * Left-aligned |
| 92 | + * |
| 93 | + * 타이틀이 좌측에 위치한 탑앱바입니다. 기능의 첫 페이지에 사용되는 탑앱바로, |
| 94 | + * 현재 페이지의 제목을 나타낼 때 사용합니다. 아이콘으로 기능을 명확하게 표현하지 못하거나 확실하게 기능을 설명하고 싶을 때 아이콘 대신 Text를 사용할 수 있습니다. |
| 95 | + * |
| 96 | + * @param title headline or Logo 최대 9자(공백 포함) |
| 97 | + * @param actions 오른쪽 아이콘 or 텍스트 (아이콘은 임의로 변경할 수 있으며 Left-aligned의 우측엔 최대 3개의 아이콘 버튼) |
| 98 | + **/ |
| 99 | +@Composable |
| 100 | +fun LeftAlignedTopAppBar( |
| 101 | + title: String, |
| 102 | + actions: @Composable (RowScope.() -> Unit)? = null |
| 103 | +) { |
| 104 | + |
| 105 | + Box( |
| 106 | + modifier = Modifier |
| 107 | + .fillMaxWidth() |
| 108 | + .background(color = HandyTheme.colors.bgBasicDefault) |
| 109 | + .height(topBarHeight) |
| 110 | + .padding(horizontal = topBarHorizontalPadding), |
| 111 | + |
| 112 | + contentAlignment = Alignment.Center |
| 113 | + ) { |
| 114 | + |
| 115 | + Text( |
| 116 | + text = title, |
| 117 | + style = HandyTypography.H3Sb24, |
| 118 | + color = HandyTheme.colors.textBasicPrimary, |
| 119 | + modifier = Modifier.align(Alignment.CenterStart) |
| 120 | + |
| 121 | + ) |
| 122 | + |
| 123 | + actions?.let { |
| 124 | + Row( |
| 125 | + verticalAlignment = Alignment.CenterVertically, |
| 126 | + horizontalArrangement = Arrangement.spacedBy(topBarActionsInsidePadding), // 요소 사이에 24dp 간격 추가 |
| 127 | + ) { |
| 128 | + Spacer(modifier = Modifier.weight(1f)) |
| 129 | + actions() |
| 130 | + } |
| 131 | + } |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | + |
| 136 | +object TopBarDefaults { |
| 137 | + val topBarHeight = 56.dp |
| 138 | + val topBarHorizontalPadding = 16.dp |
| 139 | + val topBarActionsInsidePadding = 24.dp |
| 140 | + val topBarIconPadding = 8.dp |
| 141 | +} |
0 commit comments