Jetpack Compose

[Jetpack Compose] 컴포즈 Codelab 기초 따라하기 - 2

베르_최성훈 2023. 12. 24. 17:27

 

들어가기 전에

 

컴포즈 Codelab 기초 따라하기 - 1 후속편입니다.

https://seonghoonc.tistory.com/44

 

본 글은 Jetpack Compose Codelab basics 의 상태 호이스팅 이후를 다루고 있습니다.

https://developer.android.com/codelabs/jetpack-compose-basics?hl=ko#7

 

 

 

상태 호이스팅

여러 컴포저블 함수가 읽거나 수정하는 상태는 공통된 상위 항목에 위치해야한다. 이를 상태 호이스팅이라고 한다.

호이스팅은 들어올린다 or 끌어올린다라는 의미라고 한다.

 

상태를 호이스팅의 장점

- 상태 중복 및 버그 발생을 방지할 수 있다.

- 컴포저블을 재사용할 수 있다.

- 쉽게 테스트할 수 있다.

 

그러나 상위 요소에서 제어할 필요없는 상태는 호이스팅하면 안된다.

 

온보딩 화면을 만들어 보자.

 

 

이전과 다르게 by 키워드를 사용해 위임했다.

 

이를 사용하기 위해서 두 가지 import 가 필요했다.

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

 

이 것들은 어디에 사용하는거지? 

 

inline operator 였다. 실제 컴파일하면 본문이 포함되겠지만 코드 작성시에 .value 를 입력하지 않아도 setValue, getValue 가 가능하도록 만들어준다.

 

화면 중앙에 콘텐츠를 표시할 수 있도록 Column 을 구성할 수 있다. 여기서 ArrangementAlignment 를 사용했다.

매우 자주 쓸 것 같으니 이 두 가지에 대해 간략히만 알고 넘어가보자.

 

Arrangement

수평 방향 배치이다. 즉 같은 방향에서 어떻게 배치할지 결정한다. Row 에는 Start, Center, End 등이 있고 Column 은 Top, Center, Bottom 이 존재한다 Box는 당연히 더 많다. 

Alignment

수직 정렬 방식이다. 상위 컨테이너 내부에서 어떻게 정렬할 것인지 설정할 수 있다. Column 에서 Alignment 는 Start, CenterHorizontally, End 가 있으며 Row 에는 Top, CenterVertically, Bottom 이 존재한다. Box 에는 더 많다.

 

다음에 자세하게 알아보자.

 

 

 

 

Compose 에서는 UI 요소를 숨기지 않는다. 컴포지션에 추가하지 않으므로 Compose 가 생성하는 UI 트리에 추가되지 않는다.

 

이게 무슨 말일까? view 의 visibilty 처리를 말하는 것 같다(추측).

중간에 궁금한게 많아서 잡소리가 많았는데 다시 돌아가자...상태 호이스팅! 

 

 

 

버튼을 클릭하는 이벤트 자체는 OnboardingScreen 에서 처리하지만 온보딩 뷰를 보여줄지 상태를 저장하는 것은 더 상위 컴포넌트에 존재해야한다. 여기선 MyApp(상위 컴포넌트) 의 shouldShowOnboarding 변수가 상태를 저장한다. 그런 다음 상태를 변경시킬 수 있게 OnboardingScreen(하위 컴포넌트)에 람다(함수) 형태로 콜백을 전달한다.

 

이런 방식으로 컴포저블 함수의 재사용성을 높이고 다른 컴포저블이 상태를 변경하지 않도록 보호할 수 있다.

 

 

 

 

 

성능 지연 목록 만들기

지금까지 몇 개 안되는 목록만 처리했다. 하지만 수천 개가 생긴다면 어떨까?

 

따라서 스크롤이 가능한 열을 표시하기 위해 LazyColumn 을 사용해야한다. LazyColumn 은 화면에 보이는 항목만 렌더링하기 때문에 항목이 많은 목록을 렌더링할 때 성능이 향상된다.

 

LazyColumn 과 LazyRow 는 Android View 의 RecyclerView 와 동일하다.

그럼 이 LazyColumn 가  RecyclerView 를 사용하는가? 그렇지는 않다. 컴포저블을 방출하는 것이 View 를 인스턴스화하는 것 보다 상대적으로 비용이 적게 든다. 따라서 LazyColumn 은 스크롤 할 때 새 컴포저블을 방출하고 계속 성능을 유지한다.

 

 

기본적으로 LazyColumn 은 items 를 요소를 제공한다.

 

 

상태 유지

여기까지 만들면 문제가 없어 보이지만 구성변경이 일어나면 다시 온보딩 화면이 보여진다. 앞서 상태를 저장하기 위해 사용한 remember 함수는 컴포저블이 컴포지션에 유지되는 동안에만 작동한다. 기기를 회전하면 Activity 자체가 다시 시작되기 때문에 상태가 손실된다.

 

remember 대신 rememberSaveable 을 사용하면 된다. 이 함수는 구성 변경과 프로세스 중단에도 상태를 저장한다.

 

 

 

 

 

목록에 애니메이션 적용

Compose 에서는 쉽게 애니메이션을 지정할 수 있다.

 

https://developer.android.com/jetpack/compose/animation?hl=ko

 

애니메이션에 대한 얘기는 다음에 자세히 알아보도록 하고...

 

animateDpAsState 컴포저블을 사용하자. 이 컴포저블은 애니메이션이 완료될 때까지 애니메이션에 의해 객체의 value 가 계속 업데이트 되는 상태 객체를 반환한다. 

 

앞서 정의한 extraPadding 을 targetValue 로 하여 정의해보자.

 

 

이것 만으로 애니메이션은 동작하지만 맞춤 설정을 위해서 animaitionSpec 을 사용할 수 있다. 스프링 기반의 애니메이션을 추가해보자.

 

 

먼저 패딩이 음수가 되지 않도록 해야한다. 

앱이 다운될 수 있다. 따라서 coerceAtLeast 로 최소 0dp 제한을 걸었다.

 

 

이때 사용한 Spring 사양은 물리적 속성을 사용해 애니메이션을 더 자연스럽게 만든다.

더 다양한 조작을 위해선 spring, tween, repeatable 또는 animateColorAsState 같은 함수를 사용할 수 있다.

 

 

 

 

 

앱의 스타일 지정 및 테마 설정

 

지금까지는 스타일 지정없이 기본값이었다. 이제 [프로젝트이름]Theme 과 MaterialTheme 이 무엇인지 살펴보자.

현재 프로젝트 이름이 learning-compose 이기 때문에 LearningcomposeTheme 으로 정의되어 있다.

 

LearningcomposeTheme 구현에서 MaterialTheme 을 사용하고 있는데 이 MaterialTheme 은 무엇일까?

 

MaterialTheme 은 Material 디자인 사양(specification)의 스타일 지정 원칙을 반영한 컴포저블 함수이다.

모든 하위 컴포저블에서 MaterialTheme 의 세가지 속성, colorScheme, typography, shapes 를 가져올 수 있다.

 

목록 아이템의 name 을 헤드라인 스타일로 지정해보자.

 

 

 

 

Text 컴포저블 함수에 style 을 설정해주었다. custom TextStyle 도 만들 수 있고 기본 MaterialTheme 에서 가져올 수도 있다.

 

가끔 색상이나 글꼴 스타일을 기본에서 벗어나야 할 때가 있다.

그럴 때는 copy 함수를 사용해 스타일을 수정할 수 있다.

 

 

 

 

다크 모드 Preview 설정

다크 모드 미리보기는 어떻게 볼까?

@Preview 의 uiMode 인자에 UI_MODE_NIGHT_YES 를 추가해보자

 

 

헉.. Preview 어노테이션 하나 추가해줬는데 다크모드 미리보기가 추가된다...

 

 

 

 

앱 테마 조정

ui/theme 패키지에 현재 테마와 관련된 모든 항목이 존재한다. 예를 들어 Color.kt 등이 있다.

 

새로운 색상을 정의해보자.

먼저 아래 색깔 변수들을 Color.kt 에 추가해주었다.

 

그 다음 MaterialTheme 에 할당했다.

 

다시 돌아가면 색깔이 바껴있겠지..? 라고 생각했지만 바껴있지 않다. 

미리보기는 색이 동적 결정되기 때문이다..근데 실행해도 바껴있지 않다.

 

코드를 보니 안드로이드 sdk 31 이상에서는 내가 정의한 것을 사용하고 있지 않았다.

 

 

그럼 어떻게 바꿔야하지..?

 

찾아보니 테마 설정 코드랩이 따로 있다. 동적 테마 설정은 다음에 공부해보자!

https://developer.android.com/codelabs/jetpack-compose-theming?hl=ko#0

 

Material 3을 사용하는 Compose의 테마 설정  |  Android Developers

이 Codelab의 목적은 새롭게 구현된 Material Design 3 및 Material You로 Jetpack Compose의 테마 설정을 보여주는 것입니다.

developer.android.com

 

 

설정 완료

버튼을 아이콘으로 대체

compose 의 Icon, IconButton 컴포저블을 사용한다.

 

 

추가로 문자열을 리소스로 분리했다.

 

최종 화면 (안드로이드 34)

 

마무리하며

Compose codelab basics 를 하며 재미도 있었지만 생각보다 엄청 방대하고 기능이 많은 것을 알 수 있었다. 

애니메이션 적용이나 미리보기가 편했던 것이 인상적이다!

 

추가로 공부해야할 것들이 많아보인다..화이팅!!

 

 

추가 공부 키워드

에니메이션 API 

동적 Theme 적용 (sdk 31 이상)

Arrangement & Alignment