컴포즈에는 앱을 만드는데 필요한 개발자가 사용할 수 있는 머테리얼 컴포넌트 컴포저블이 딸려있다. 가장 높은 수준의 컴포저블은 Scaffold다.
Scaffold
Scaffold(발판)는 기초적인 머테리얼 디자인 레이아웃 구조를 구현할 수 있도록 도와준다. TopAppBar, BottomAppBar, FloatingActionButton 및 Drawer와 같은 가장 일반적인 최상위 머테리얼 컴포넌트에 대한 Slot을 제공한다. Scaffold를 사용하면 이러한 컴포넌트들을 배치하고 올바르게 동작하도록 한다.
안드로이드 스튜디오에서 생성한 템플릿을 기반으로, 샘플 코드를 수정하여 Scaffold를 사용해보자. MainActivity.kt를 열고 더 이상 사용하지 않을 Greeting 및 GreetingPreview 컴포저블을 삭제하자.
LayoutsCodelab 라는 이름으로 새로운 컴포저블을 생성하여, 이 코드랩을 통해 수정해보도록 하자.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LayoutsCodelabTheme {
LayoutsCodelab()
}
}
}
}
@Composable
fun LayoutsCodelab() {
Text(text = "Hi there!")
}
@Preview
@Composable
fun LayoutsCodelabPreview() {
LayoutsCodelabTheme {
LayoutsCodelab()
}
}
컴포즈 @Preview 애노테이션이 붙어있는 미리보기 함수를 살펴보면 LayoutCodelab이 다음과 같이 나타난다.
예제에 Scaffold 컴포저블 추가하여 전형적인 머테리얼 디자인 구조를 가질 수 있도록 하자. Scaffold API의 모든 매개변수는 @Composable (InnerPadding) -> Unit 타입의 content를 제외하고는 선택사항이다. 이 content 람다식의 매개변수는 padding을 매개변수로 받는데, 이는 화면에 들어가는 아이템들을 적절하게 제한하기 위해 최상위 컴포저블에 적용하는 패딩이다. 일단 이해하기 쉽도록 단순하게 시작하기 위해, Scaffold를 다른 머테리얼 컴포넌트 없이 추가해보도록 하자.
@Composable
fun LayoutsCodelab() {
Scaffold { innerPadding ->
Text(text = "Hi there!", modifier = Modifier.padding(innerPadding))
}
}
미리보기로 확인하면 다음과 같다.
화면에 메인 컨텐츠를 Column과 함께 넣기를 원하면, Column의 Modifier를 다음과 같이 적용하자.
@Composable
fun LayoutsCodelab() {
Scaffold { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
Text(text = "Hi there!")
Text(text = "Thanks for going through the Layouts codelab")
}
}
}
미리보기로 보면 다음과 같다.
코드의 재사용성과 테스트 용이성을 더 좋게 만들기 위해서, 작은 단위로 구조를 짜야한다. 그러기 위해서는 화면의 컨텐츠와 함께 또 다른 컴포저블 함수를 생성해야 한다.
@Composable
fun LayoutsCodelab() {
Scaffold { innerPadding ->
BodyContent(Modifier.padding(innerPadding))
}
}
@Composable
fun BodyContent(modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(text = "Hi there!")
Text(text = "Thanks for going through the Layouts codelab")
}
}
안드로이드에서는 상단 AppBar에 현재 화면, 네비게이션, 액션에 대한 정보를 보여주는 것이 일반적이다. 예제에 이런 점을 지금 추가해보자.
TopAppBar
Scaffold는 @Composable() -> Unit 타입의 topBar 매개변수와 함께 상단 AppBar를 위한 slot을 가지고 있다. 이것이 의미하는 점은 슬롯에 우리가 원하는 어떤 컴포저블도 채워 넣을 수 있다는 것이다. 예를들어, h3 스타일의 텍스트를 포함하길 원하면 slot에 Text를 사용하기만 하면된다. 다음 코드를 살펴보자.
@Composable
fun LayoutsCodelab() {
Scaffold(
topBar = {
Text(
text = "LayoutsCodelab",
style = MaterialTheme.typography.h3
)
}
) { innerPadding ->
BodyContent(Modifier.padding(innerPadding))
}
}
미리보기상으로는 다음과 같이 나온다.
그러나 컴포즈에서 대부분의 머테리얼 컴포넌트를 보면 타이틀, 네비게이션 아이콘 및 액션을 위한 슬롯을 갖는 TopAppBar 컴포넌트가 딸려있다. 또한, 각 컴포넌트에 사용할 색상과 같이 머테리얼 스펙에서 권장하는 사항에 맞게 조정되는 일부 기본값이 함께 제공된다.
다음 slot API 패턴을 보면, TopAppBar의 title 슬롯에 화면 제목을 갖는 Text를 배치하고 있다.
@Composable
fun LayoutsCodelab() {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "LayoutsCodelab")
}
)
}
) { innerPadding ->
BodyContent(Modifier.padding(innerPadding))
}
}
미리보기에서는 다음과 같이 나온다.
상단 AppBar들은 보통 action 항목들을 갖는다. 여기 나오는 예제에서, 무언가 배웠다고 생각이 들 때, 탭 할 수 있는 즐겨찾기(favorite) 버튼을 추가해보자. 컴포즈는 또한 우리가 사용할 수 있는 미리 정의된 머테리얼 아이콘을 포함하고 있는데, 예를 들면 닫기(close), 즐겨찾기(favorite) 및 메뉴(menu) 가 있다.
상단 AppBar에 action 아이템들을 위한 slot은 actions 매개변수로 받는데, 이는 내부적으로 Row를 사용한다. 그래서 다수의 action을 수평적으로 배치한다. 미리 정의된 아이콘들중 하나를 사용하기 위해, 우린 IconButton 컴포저블에 내부에 Icon을 사용할 수 있다.
@Composable
fun LayoutsCodelab() {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "LayoutsCodelab")
},
actions = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Favorite, contentDescription = null)
}
}
)
}
) { innerPadding ->
BodyContent(Modifier.padding(innerPadding))
}
}
미리보기로 확인하면 다음과 같다.
보통의 경우, action들은 애플리케이션의 상태(state)를 수정한다. 상태에 대한 더 많은 정보는 Basics Compose codelab에서 상태관리의 기초에 대해 배울 수 있다.
Modifier 배치하기
새로운 컴포저블을 생성할 때마다, 기본값을 갖는 Modifier 매개변수의 사용은 컴포저블을 좀 더 재사용하기 좋은 방법이다. 아래에 나올 BodyContent 컴포저블은 이미 Modifier를 매개변수로 취하고 있다. 만약 더 많은 여백을 갖도록 padding값을 BodyContent에 추가하고 싶다면, padding이 포함된 Modifier를 어디에 배치해야 하는게 좋을까?
두가지 가능성을 고려해볼 수 있다.
- 1. Modifier를 직접적으로 자식 컴포저블에만 적용하여, BodyContent에 대한 모든 호출이 추가적인 여백을 적용할 수 있도록 하는 것
@Composable
fun BodyContent(modifier: Modifier = Modifier) {
Column(modifier = modifier.padding(8.dp)) {
Text(text = "Hi there!")
Text(text = "Thanks for going through the Layouts codelab")
}
}
- 2. 컴포저블을 호출할 때 Modifier를 적용하여 필요할 때 추가적인 여백을 더하는 것
@Composable
fun LayoutsCodelab() {
Scaffold(...) { innerPadding ->
BodyContent(Modifier.padding(innerPadding).padding(8.dp))
}
}
이것은 전적으로 컴포저블 형식 및 유즈케이스를 보고 결정할 수 있다. Modifier가 컴포저블에 본질적인 부분이라면, 이를 안쪽에 배치하도록 하자. 만약에 그게 아니라면, 밖에 배치하자. 우리의 경우 padding이 BodyContent를 호출할 때마다 항상 강제로 적용되지 않을 수 있으므로 두번째 옵션을 선택하자. 이건 정말 case-by-case임을 유의하자.
Modifier는 이전에 호출한 Modifier 함수를 통해 체이닝을 할 수 있다. 체이닝이 불가능한 메서드를 호출했을때는 .then()을 사용할 수 있다. 우리 예제에서는 modifier로 체이닝을 시작하는데, 이는 체이닝이 매개변수로 전달된 modifier에 계속하여 체이닝되는 것을 의미한다.
더 많은 아이콘들
이전에 소개한 아이콘들은 제외하고, 프로젝트에 새로운 의존성을 추가하는 것으로 전체 머테리얼 아이콘 목록을 사용할 수 있다. 이 아이콘들을 실험해보고 싶다면, app/build.gradle 파일을 열어서 ui-material-icons-extended 의존성을 추가한다.
dependencies {
...
implementation "androidx.compose.material:material-icons-extended:$compose_version"
}
이제 원하는 만큼 TopAppBar의 아이콘들을 어서 변경해보도록 하자!
추가 작업
Scaffold 및 TopAppBar는 단지 머테리얼 디자인을 갖는 애플리케이션을 위해 사용되어지는 컴포저블에 불과하다. BottomNavigation 또는 BottomDrawer와 같은 다른 머테리얼 컴포넌트에 대해서도 동일한 작업을 수행할 수 있다. 연습으로 지금까지 우리가 해왔던 겉과 같은 방식으로 이러한 API과 함께 Scaffold의 Slot들을 채워보도록 하자.
0개의 댓글