기존의 안드로이드 UI 개발 방식인 XML 기반의 레이아웃과 달리 Compose는 Kotlin 언어를 기반으로 한 UI 작성 방식이다.
Compose는 "Composable"이라 불리는 UI 구성 요소들을 조합하여 UI를 구성한다.
XML을 작성하지 않아서 관리할 코드가 줄어든다.
작성자는 테스트와 디버그 작업과 버그 발생 가능성이 줄어들어 당면 문제에 집중할 수 있다.
검토자 또는 유지관리자는 읽고, 이해하고, 검토하고, 유지관리할 코드가 적어진다.
Compose는 선언적 API를 사용한다. 즉, Compose가 나머지를 처리하므로 UI를 설명하기만 하면 된다.
Compose를 사용하면 특정 활동이나 프래그먼트에 종속되지 않는 작은 스테이트리스(Stateless) 구성요소를 빌드한다.
이를 통해 재사용하고 테스트하기가 쉬워진다.
Compose는 기존의 모든 코드와 호환 가능하다.
Compose에서 Views를, Views에서 Compose 코드를 호출할 수 있다.
Navigation, ViewModel, Kotlin 코루틴과 같은 대부분의 일반적인 라이브러리는 Compose와 함께 작동하므로 언제 어디서든 원하는 대로 채택 가능하다.
머티리얼 디자인을 활용하여 애니메이션, 아름다운 디자인을 적극 활용할 수 있다.
@Preview
@Composable
fun PreviewMessageCard() {
MessageCard(
msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
)
}
// Material Design 스타일 지정을 사용하여 MessageCard 컴포저블의 디자인을 개선
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES, // 다크 모드
showBackground = true,
name = "Dark Mode"
)
@Composable
fun PreviewMessageCard2() {
ComposeTutorialTheme {
Surface {
MessageCard(
msg = Message("Colleague", "Take a look at Jetpack Compose, it's great!")
)
}
}
}
@Preview를 사용하면 화면 오른쪽에서 해당 코드의 디자인을 확인 할 수 있다.
@Composable은 해당 함수를 Compose로 표현할 수 있음을 의미한다.
MessageCard는 아래와 같다.
data class Message(val author: String, val body: String)
@Composable
fun MessageCard(msg: Message) {
// 전체에 패딩 8dp를 준다.
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "picture",
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
// 수평으로 8dp의 공간을 준다.
Spacer(modifier = Modifier.width(8.dp))
Column() {
Text(
text = msg.author,
color = MaterialTheme.colors.secondaryVariant, // 글자 색
style = MaterialTheme.typography.subtitle2 // 서체
)
// 수직으로 4dp의 공간을 준다.
Spacer(modifier = Modifier.height(4.dp))
Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
Text(
text = msg.body,
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(all = 4.dp)
)
}
}
}
}
대화형 화면을 출력하는 코드는 다음과 같다.
@Composable
fun Conversation(messages: List<Message>) {
LazyColumn {
items(messages) { message ->
MessageCard(message)
}
}
}
@Preview
@Composable
fun PreviewConversation() {
ComposeTutorialTheme {
Conversation(SampleData.conversationSample)
}
}
대화 내용을 1줄로 줄이고 클릭시 대화 내용을 펼치는 애니메이션을 사용한 코드는 아래와 같다.
fun MessageCard(msg: Message) {
// 전체에 패딩 8dp를 준다.
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
...
)
...
// We keep track if the message is expanded or not in this
// variable
var isExpanded by remember { mutableStateOf(false) }
// 클릭하면 isExpanded의 상태를 변경한다.
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
...
Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
Text(
text = msg.body,
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(all = 4.dp),
// isExpanded의 값에 따라 값을 수정한다. -> 펼쳤다 줄었다 함.
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
)
}
}
}
}
펼쳤을 때 색 변경과 애니메이션을 위해 아래의 코드를 추가 작성할 수 있다.
val surfaceColor by animateColorAsState(
if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
)
Surface(
shape = MaterialTheme.shapes.medium,
elevation = 1.dp,
// surfaceColor color will be changing gradually from primary to surface
color = surfaceColor,
// animateContentSize will change the Surface size gradually
modifier = Modifier.animateContentSize().padding(1.dp)
)
LazyColumn
LazyRow
remember