TIL240422 컴포즈 시작해보기

jericho·2024년 4월 22일

TIL

목록 보기
53/62

프로젝트 시작하기

컴포즈 기본 코드로 시작하는 방법은 간단하다.
안드로이드 스튜디오에서 새 프로젝트를 만들 때 Empty Activity를 선택해서 만들면 기본적으로 컴포즈를 사용하도록 구성되어있다.

이것저것

뷰? 위젯? 구성요소? 뭐라 불러야 할지 모르겠는데 아무튼 이걸 Surface로 감싸서 color = MaterialTheme.colorScheme.primary 등 색 테마를 넣어주면 되는 모양이다.
근데 이건 MyApp 같은 가장 큰 단위에서 해주는 모양..? 아직 잘 모르겠는 부분이다.

지금까지 본 바로는 modifier가 핵심같다.
여기에 .padding(24.dp) .fillMaxWidth() 등등 붙여나간다.
근데 컴포즈 함수에 modifier를 매개변수로 받는데, 이건 가장 바깥 놈 하나한테만 사용하고 나머지는 Modifier를 생성?해서 사용함. 아직은 뭔지 잘 모르겠다.

Row 랑 Column으로 LinearLayout 처럼 만들어나가는데, xml이 아니라 코드로 구성하다보니 for문으로 추가가 가능한 부분이 강력하다.
레이아웃을 잘 생각해서 감싸줘야 한다.

//
Row(modifier = Modifier.padding(24.dp)) {
    Column(
        modifier = Modifier
            .weight(1f)
            .padding(bottom = extraPadding)
    ) {
        Text(text = "Hello")
        Text(text = "$name!")
    }
    ElevatedButton(onClick = { expanded = !expanded }) {
        Text(if (expanded) "Show less" else "Show more")
    }
}

뭔가 이렇게 했더니 버튼이랑 텍스트가 각각 왼쪽 오른쪽으로 자동으로 가서 붙어있는 것 같은데, 잘 모르겠다.

Preview에 너비랑 높이 줘서 디바이스 사이즈?처럼 지정할 수 있다.
@Preview(showBackground = true, widthDp = 320)

State

컴포즈에서 상태를 다룰 때에는 mutableStateOf 으로 만들어 쓰고, remember로 감싸서 저장?한다.
val expanded = remember { mutableStateOf(false) }
사용할 때는 LiveData랑 비슷하게 .value로 get set 해준다.

그런데 이걸 간편하게 해주기 위해 by remember로 하면 그냥 변수처럼 사용할 수 있게 된다. 변수처럼 사용되니 val로 하면 변경이 안되므로 var로 사용해준다.
var shouldShowOnboarding by remember { mutableStateOf(true) }

근데 신기한 점은
val extraPadding = if (expanded) 48.dp else 0.dp
이렇게만 해놨는데
modifier.padding(bottom = extraPadding)
이렇게 수정자에 extraPadding을 설정해놨을 뿐인데
expanded 값이 바뀌면 자동으로 extraPadding 값도 바뀌어 적용된다는 것이다.
단순한 Boolean 변수가 추적이 될 리도 없고 변경도 안되는데 말이다.
상태가 바뀌면 컴포즈?를 다시 그리는 걸까...?

State Hoisting

컴포저블 함수에서 여러 함수가 읽거나 수정하는 상태는 공통의 상위 항목에 위치해야 함.
이 프로세스를 '상태 호이스팅'이라고 함.
(호이스팅이란 들어올린다 또는 끌어올린다 라는 의미)

  • 장점
    • 상태 중복 방지
    • 버그 방지
    • 컴포저블 재사용 가능
    • 테스트 용이

한편, 컴포저블의 상위 요소에서 제어할 필요가 없는 상태는 호이스팅되면 안됨.
'정보 소스'는 상태를 생성하고 관리하는 대상에 속함...? 뭔말인지 모르겠다.

한마디로 호이스팅은 상위 항목에 상태를 두고, 해당 상태에 접근해야 하는 다른 항목에 람다식 등으로 변경할 수 있도록 제공해주면 되는 것 같다.

//
@Composable
fun MyApp(modifier: Modifier = Modifier) {

    var shouldShowOnboarding by remember { mutableStateOf(true) }

    Surface(modifier) {
        if (shouldShowOnboarding) {
            OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
        } else {
            Greetings()
        }
    }
}

OnboardingScreen에서 버튼을 누르면 shouldShowOnboarding 변수를 false로 바꿔줘야 하는데, 해당 상태를 MyApp에서 체크해서 다른 항목을 띄워줘야 하니까 둘 모두 같은 상태를 읽고 써야한다. 그러므로 상위 항목인 MyApp에 상태를 두고 OnboardingScreen에 람다식을 넘겨줘서 버튼 눌렀을 때 해당 상태를 false로 바꿔주도록 제공해준 것. 이게 호이스팅이라고 한다.

의문점

margin 옵션이 없는건가...? 안보인다.
버튼에 패딩만 줬는데 마진처럼 작동하기도 하고.

0개의 댓글