Compose Tutorial

k_hyun·2023년 6월 14일
0

Compose

기존의 안드로이드 UI 개발 방식인 XML 기반의 레이아웃과 달리 Compose는 Kotlin 언어를 기반으로 한 UI 작성 방식이다.
Compose는 "Composable"이라 불리는 UI 구성 요소들을 조합하여 UI를 구성한다.

Why Compose?

코드 감소

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

  • remember는 메모리에 객체를 저장하는 API다. 계산되어 만들어진 값은 컴포지션 도중에 저장되어 리컴포지션 도중에 반환된다
  • remember로 변경 가능한 객체, 변경 불가능한 객체 모두를 저장할 수 있다
  • remember를 호출하면 UI 전체를 다시 그리는 게 아니라 변경이 필요한 부분만 변경한다.
  • mutableStateOf()라는 함수를 자주 사용해 바뀌는 값을 관리한다

0개의 댓글