Android용 Material 모션을 사용하여 멋진 전환 빌드

1. 소개

Material Design은 대담하고 멋진 디지털 제품을 빌드하는 시스템입니다. 일련의 일관된 원칙과 구성요소 아래 스타일과 브랜딩, 상호작용, 모션을 통합하여 제품팀은 가능한 최고의 디자인을 실현할 수 있습니다.

logo_components_color_2x_web_96dp.png

머티리얼 구성요소(MDC)를 통해 개발자는 머티리얼 디자인을 구현할 수 있습니다. Google의 엔지니어와 UX 디자이너로 구성된 팀에서 만든 MDC는 아름답고 기능적인 수십 가지의 UI 구성요소가 특징이며 Android, iOS, 웹, Flutter.material.io/develop에서 제공됩니다.

Android용 Material 모션 시스템이란 무엇인가요?

Android용 Material Motion System은 MDC-Android 라이브러리 내에 있는 일련의 전환 패턴으로, Material Design 가이드라인에 설명된 것처럼 사용자가 앱을 파악하고 탐색하는 데 도움이 됩니다.

주요 머티리얼 전환 패턴 네 가지는 다음과 같습니다.

  • 컨테이너 변환: 컨테이너가 포함된 UI 요소 간 전환. 한 요소에서 다른 요소로 매끄럽게 변환하여 고유한 두 UI 요소 사이에 시각적인 연결을 만듭니다.
  • 공유 축: 공간 관계나 탐색 관계가 있는 UI 요소 간 전환. x축이나 y축, z축에서 공유 변환을 사용하여 요소 간 관계를 강화합니다.
  • 페이드 스루: 서로 관계가 밀접하지 않은 UI 요소 간 전환. 들어오는 요소의 배율과 함께 순차적인 페이드 아웃과 페이드 인을 사용합니다.
  • 페이드: 화면 경계 내에서 나타나거나 사라지는 UI 요소에 사용됩니다.

MDC-Android 라이브러리는 AndroidX 전환 라이브러리 (androidx.transition)와 Android 전환 프레임워크 (android.transition)를 기반으로 빌드된 이러한 패턴의 전환 클래스를 제공합니다.

AndroidX

  • com.google.android.material.transition 패키지에서 사용 가능
  • API 수준 14 이상 지원
  • 프래그먼트와 뷰는 지원하지만 활동이나 창은 지원하지 않음
  • 백포팅된 버그 수정사항과 API 수준 전반에서 일관된 동작이 포함되어 있습니다.

프레임워크

  • com.google.android.material.transition.platform 패키지에서 사용 가능
  • API 수준 21 이상 지원
  • 프래그먼트, 뷰, 활동 및 Windows 지원
  • 버그 수정이 백포트되지 않았으며 API 수준 간에 동작이 다를 수 있음

이 Codelab에서는 AndroidX 라이브러리를 기반으로 빌드된 Material 전환을 사용합니다. 즉, 주로 프래그먼트와 뷰에 중점을 둡니다.

빌드할 항목

이 Codelab에서는 Kotlin을 사용하여 Reply라는 Android 이메일 앱으로 전환을 빌드하는 방법을 안내합니다. 이를 통해 MDC-Android 라이브러리의 전환을 사용하여 앱의 디자인과 분위기를 맞춤설정하는 방법을 보여줍니다.

Reply 앱의 시작 코드가 제공되고 아래 완료된 Codelab의 GIF에서 확인할 수 있는 다음 머티리얼 전환을 앱에 통합합니다.

  • 이메일 목록에서 이메일 세부정보 페이지로 컨테이너 변환 전환
  • FAB에서 이메일 작성 페이지로 컨테이너 변환 전환
  • 검색 아이콘에서 검색 뷰 페이지로 공유 Z축 전환
  • 편지함 페이지 간 페이드 스루 전환
  • 이메일 주소 칩에서 카드 보기로 컨테이너 변환 전환

요청된 iframe (youtu.be)의 도메인이 허용 목록에 없습니다.

필요한 항목

  • Android 개발 및 Kotlin에 관한 기본 지식
  • Android 스튜디오(아직 다운로드하지 않은 경우 여기에서 다운로드)
  • Android Emulator 또는 기기(Android 스튜디오를 통해 사용 가능)
  • 샘플 코드(다음 단계 참고)

Android 앱 빌드 경험 수준을 평가해 주세요.

초급 중급 고급

2. 개발 환경 설정

Android 스튜디오 시작

Android 스튜디오를 열면 'Welcome to Android Studio'라는 창이 표시됩니다. 그러나 Android 스튜디오를 처음 실행하는 경우 기본값을 사용하여 Android 스튜디오 설정 마법사 단계를 진행합니다. 이 단계는 필요한 파일을 다운로드하고 설치하는 데 몇 분 정도 걸릴 수 있으므로 다음 섹션을 진행하는 동안 이 작업이 백그라운드에서 실행되도록 하면 됩니다.

옵션 1: GitHub에서 시작 Codelab 앱 클론

Codelab을 GitHub에서 클론하려면 다음 명령어를 실행합니다.

git clone https://github.com/material-components/material-components-android-motion-codelab.git
cd material-components-android-motion-codelab

옵션 2: 시작 Codelab 앱 zip 파일 다운로드

시작 앱은 material-components-android-motion-codelab-develop 디렉터리에 있습니다.

Android 스튜디오에서 시작 코드 로드

  1. 설정 마법사가 완료되고 Welcome to Android Studio 창이 표시되면 Open an existing Android Studio project를 클릭합니다.

e3f200327a67a53.png

  1. 샘플 코드를 설치한 디렉터리로 이동하고 샘플 디렉터리를 선택하여 프로젝트를 엽니다.
  2. Android 스튜디오 창 하단의 활동 표시기에 나타나는 것처럼 Android 스튜디오가 프로젝트를 빌드하고 동기화할 때까지 잠시 기다립니다.
  1. 이 시점에서 Android 스튜디오에 아래와 같은 빌드 오류가 발생할 수 있습니다. Android SDK나 빌드 도구가 누락되었기 때문입니다. Android 스튜디오의 안내를 따라 이러한 항목을 설치/업데이트하고 프로젝트를 동기화합니다. 여전히 문제가 발생한다면 SDK Manager로 도구 업데이트 가이드를 따르세요.

6e026ae171f5b1eb.png

프로젝트 종속 항목 확인

프로젝트에는 MDC-Android 라이브러리의 종속 항목이 필요합니다. 다운로드한 샘플 코드에는 이 종속 항목이 이미 나열되어 있지만 구성을 살펴보며 확인해보겠습니다.

app 모듈의 build.gradle 파일로 이동하여 dependencies 블록에 MDC-Android 종속 항목이 포함되어 있는지 확인합니다.

implementation 'com.google.android.material:material:1.2.0'

시작 앱 실행

  1. 기기 선택 왼쪽에 있는 빌드 구성이 app인지 확인합니다.
  2. 녹색 실행/재생 버튼을 눌러 앱을 빌드하고 실행합니다.

24218d0a6ae25803.png

  1. 사용 가능한 기기에 Android 기기가 이미 나열되어 있으면 Select Deployment Target 창에서 8단계로 건너뜁니다. 나열되어 있지 않으면 Create New Virtual Device를 클릭합니다.
  2. Select Hardware 화면에서 Pixel 3와 같은 휴대전화 기기를 선택한 후 Next를 클릭합니다.
  3. System Image 화면에서 최신 Android 버전(가장 높은 API 수준 권장)을 선택합니다. 설치되어 있지 않은 경우 표시되는 다운로드 링크를 클릭하고 다운로드를 완료합니다.
  4. Next를 클릭합니다.
  5. Android Virtual Device(AVD) 화면에서 설정을 그대로 두고 Finish를 클릭합니다.
  6. 배포 대상 대화상자에서 Android 기기를 선택합니다.
  7. 확인을 클릭합니다.
  8. Android 스튜디오가 앱을 빌드하고 배포한 후 자동으로 대상 기기에서 앱을 엽니다.

완료되었습니다. Reply의 홈페이지 시작 코드가 에뮬레이터에서 실행되고 이메일 목록이 포함된 받은편지함이 표시됩니다.

cc73eb0d0f779035.png

선택사항: 기기 애니메이션 속도 늦추기

이 Codelab에는 빠르면서도 세련된 전환이 포함되어 있으므로 구현하는 동안 전환을 자세하게 관찰하기 위해 기기 애니메이션 속도를 늦추는 것이 유용할 수 있습니다. adb 셸 명령어 또는 빠른 설정 타일을 사용하여 이 작업을 수행할 수 있습니다. 기기 애니메이션의 속도를 늦추는 이러한 메서드는 Reply 앱 외부의 기기 애니메이션에도 영향을 미칩니다.

방법 1: ADB 셸 명령어

기기의 애니메이션 속도를 10배 느리게 하려면 명령줄에서 다음 명령어를 실행하면 됩니다.

adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10

기기의 애니메이션 속도를 일반으로 되돌리려면 다음 명령어를 실행합니다.

adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1

방법 2: 빠른 설정 타일

또는, 빠른 설정 타일을 설정하려면, 이전에 기기에서 개발자 설정을 활성화하지 않은 경우 먼저 활성화하세요.

  1. 기기의 '설정' 앱을 엽니다.
  2. 하단으로 스크롤하여 '에뮬레이션된 기기 정보'를 클릭합니다.
  3. 하단으로 스크롤하고 개발자 설정이 사용 설정될 때까지 '빌드 번호'를 빠르게 클릭합니다.

그런 다음, 계속해서 기기의 '설정' 앱 내에서 다음을 수행하여 빠른 설정 타일을 활성화합니다.

  1. 화면 상단의 검색 아이콘 또는 검색창을 클릭합니다.
  2. 검색창에 'tiles'를 입력합니다.
  3. '빠른 설정 개발자 타일' 행을 클릭합니다.
  4. '창 애니메이션 배율' 스위치를 클릭합니다.

마지막으로 Codelab 전체에서 화면 상단에서 시스템 알림 창을 아래로 당기고 c7e3f98200023f6a.png 아이콘을 사용하여 저속 애니메이션과 일반 속도 애니메이션 간에 전환합니다.

3. 샘플 앱 코드 익히기

이제 코드를 살펴보겠습니다. Google에서는 Jetpack Navigation 구성요소 라이브러리를 사용하여 단일 활동 MainActivity 내에서 여러 Fragment 간에 이동하는 앱을 제공했습니다.

  • HomeFragment: 이메일 목록을 표시합니다.
  • EmailFragment: 하나의 전체 이메일을 표시합니다.
  • ComposeFragment:를 통해 새 이메일을 작성할 수 있습니다.
  • SearchFragment: 검색 뷰를 표시합니다.

먼저 앱의 탐색 그래프가 설정된 방식을 이해하려면 app -> src -> main -> res -> navigation 디렉터리에서 navigation_graph.xml를 엽니다.

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/navigation_graph"
   app:startDestination="@id/homeFragment">

   <fragment
       android:id="@+id/homeFragment"
       android:name="com.materialstudies.reply.ui.home.HomeFragment"
       android:label="HomeFragment">
       <argument...>
       <action
           android:id="@+id/action_homeFragment_to_emailFragment"
           app:destination="@id/emailFragment" />
   </fragment>
   <fragment
       android:id="@+id/emailFragment"
       android:name="com.materialstudies.reply.ui.email.EmailFragment"
       android:label="EmailFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/composeFragment"
       android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
       android:label="ComposeFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/searchFragment"
       android:name="com.materialstudies.reply.ui.search.SearchFragment"
       android:label="SearchFragment" />
   <action
       android:id="@+id/action_global_homeFragment"
       app:destination="@+id/homeFragment"
       app:launchSingleTop="true"
       app:popUpTo="@+id/navigation_graph"
       app:popUpToInclusive="true"/>
   <action
       android:id="@+id/action_global_composeFragment"
       app:destination="@+id/composeFragment" />
   <action
       android:id="@+id/action_global_searchFragment"
       app:destination="@+id/searchFragment" />
</navigation>

위에서 언급한 모든 프래그먼트가 어떻게 표시되는지 확인합니다. 기본 실행 프래그먼트는 app:startDestination="@id/homeFragment"를 통해 HomeFragment로 설정됩니다. 프래그먼트 대상 그래프의 XML 정의와 작업은 전환을 연결할 때 접하게 될 생성된 Kotlin 탐색 코드에 알립니다.

activity_main.xml

다음으로 app -> src -> main -> res -> layout 디렉터리의 activity_main.xml 레이아웃을 살펴봅니다. 위의 탐색 그래프로 구성된 NavHostFragment가 표시됩니다.

<fragment
   android:id="@+id/nav_host_fragment"
   android:name="androidx.navigation.fragment.NavHostFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:defaultNavHost="true"
   app:navGraph="@navigation/navigation_graph"/>

NavHostFragment는 화면을 채우고 앱의 모든 전체 화면 프래그먼트 탐색 변경사항을 처리합니다. activity_main.xml에 있는 BottomAppBar 및 고정된 FloatingActionButtonNavHostFragment에서 표시되는 현재 프래그먼트 위에 배치되므로 제공된 샘플 앱 코드의 프래그먼트 대상에 따라 표시되거나 숨겨집니다.

또한 activity_main.xmlBottomNavDrawerFragment는 다양한 이메일 보관함 간에 이동하는 메뉴가 포함된 하단 창으로, BottomAppBar 답장 로고 버튼을 통해 조건부로 표시됩니다.

MainActivity.kt

마지막으로, 사용되는 탐색 작업의 예를 보려면 app -> src -> main -> java -> com.materialstudies.reply.ui 디렉터리에서 MainActivity.kt를 엽니다. 다음과 같은 navigateToSearch() 함수를 찾습니다.

private fun navigateToSearch() {
   val directions = SearchFragmentDirections.actionGlobalSearchFragment()
   findNavController(R.id.nav_host_fragment).navigate(directions)
}

이를 통해 맞춤 전환 없이 검색 뷰 페이지로 이동하는 방법을 확인할 수 있습니다. 이 Codelab에서는 Reply의 MainActivity와 4개의 기본 프래그먼트를 자세히 살펴보고 앱 전반에 걸쳐 다양한 탐색 작업과 함께 작동하는 머티리얼 전환을 설정합니다.

시작 코드를 알아봤으므로 이제 첫 번째 전환을 구현해보겠습니다.

4. 이메일 목록에서 이메일 세부정보 페이지로의 컨테이너 변환 전환 추가

먼저 이메일을 클릭할 때 전환을 추가합니다. 이러한 탐색 변경의 경우에는 컨테이너 변환 패턴이 적합합니다. 컨테이너가 포함된 UI 요소 간 전환을 위해 설계되었기 때문입니다. 이 패턴은 두 UI 요소 간 시각적인 연결을 만듭니다.

코드를 추가하기 전에 Reply 앱을 실행하여 이메일을 클릭해보세요. 간단한 점프컷이 실행됩니다. 즉, 화면이 전환 없이 대체됩니다.

f0e8a92eb2216bce.gif

먼저 다음 스니펫과 같이 email_item_layout.xmlMaterialCardViewtransitionName 속성을 추가합니다.

email_item_layout.xml

android:transitionName="@{@string/email_card_transition_name(email.id)}"

전환 이름은 매개변수가 있는 문자열 리소스를 사용합니다. EmailFragment의 각 transitionName가 고유하도록 하려면 각 이메일의 ID를 사용해야 합니다.

이제 이메일 목록 항목의 전환 이름을 설정했으므로 이메일 세부정보 레이아웃에서도 동일하게 진행해 보겠습니다. fragment_email.xml에서 MaterialCardViewtransitionName를 다음 문자열 리소스로 설정합니다.

fragment_email.xml

android:transitionName="@string/email_card_detail_transition_name"

HomeFragment.kt에서 onEmailClicked의 코드를 아래 스니펫으로 대체하여 시작 뷰 (이메일 목록 항목)와 최종 뷰 (이메일 세부정보 화면)에서 매핑을 만듭니다.

HomeFragment.kt

val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)

이제 배관을 구성했으므로 컨테이너 변환을 만들 수 있습니다. EmailFragment onCreate 메서드에서 다음 스니펫을 추가하여 sharedElementEnterTransitionMaterialContainerTransform의 새 인스턴스로 설정합니다 (com.google.android.material.transition.platform 버전이 아닌 com.google.android.material.transition 버전 가져오기).

EmailFragment.kt

sharedElementEnterTransition = MaterialContainerTransform().apply {
   drawingViewId = R.id.nav_host_fragment
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}

이제 앱을 다시 실행해봅니다.

ed62cedec31da268.gif

점점 완벽해지고 있습니다. 이메일 목록에서 이메일을 클릭하면 컨테이너 변환으로 목록 항목이 전체 화면 세부정보 페이지로 펼쳐집니다. 그러나 뒤로를 눌러도 이메일이 목록으로 다시 접히지 않습니다. 또한 전환이 시작될 때 이메일 목록이 즉시 사라져 회색 창 배경이 표시됩니다. 따라서 아직 작업이 완료되지 않았습니다.

돌아가기 전환을 수정하려면 HomeFragment.ktonViewCreated 메서드에 다음 두 줄을 추가합니다.

HomeFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

앱을 다시 실행해 보세요. 이메일을 연 후 뒤로를 누르면 이메일이 목록으로 다시 접힙니다. 좋은 소식입니다. 애니메이션을 계속 개선해 보겠습니다.

이메일 목록이 사라지는 문제는 탐색 구성요소를 사용하여 새 프래그먼트로 이동할 때 현재 프래그먼트가 즉시 삭제되고 새로 수신되는 프래그먼트로 대체되기 때문입니다. 교체된 후에도 이메일 목록이 계속 표시되도록 하려면 HomeFragment에 나가기 전환을 추가하면 됩니다.

아래 스니펫을 HomeFragment onEmailClicked 메서드에 추가하여 이메일 목록을 종료할 때 자연스럽게 확장되고 다시 입력할 때 다시 표시되도록 합니다.

HomeFragment.kt

exitTransition = MaterialElevationScale(false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

다음으로, 계층 구조의 각 개별 뷰가 아닌 MaterialElevationScale 전환이 홈 화면 전체에 적용되도록 하려면 fragment_home.xmlRecyclerView를 전환 그룹으로 표시합니다.

fragment_home.xml

android:transitionGroup="true"

이 단계에서는 완전히 작동하는 컨테이너 변환이 있어야 합니다. 이메일을 클릭하면 목록 항목이 세부정보 화면으로 펼쳐지면서 이메일 목록은 사라집니다. 뒤로를 누르면 이메일 세부정보 화면이 다시 목록 항목으로 접히면서 이메일 목록이 나타납니다.

9df2b39d5a150418.gif

5. FAB에서 이메일 작성 페이지로의 컨테이너 변환 전환 추가

컨테이너 변환을 계속 진행하면서 플로팅 작업 버튼에서 ComposeFragment로의 전환을 추가하여 FAB를 사용자가 작성할 새 이메일로 확장해 보겠습니다. 먼저 앱을 다시 실행하고 FAB를 클릭하여 이메일 작성 화면을 실행할 때 전환이 없는지 확인합니다.

d242c9708abd382c.gif

전환 클래스는 동일하지만 FAB가 MainActivity에 있고 ComposeFragmentMainActivity 탐색 호스트 컨테이너 내에 배치되므로 이 인스턴스를 구성하는 방법은 다릅니다.

ComposeFragment.kt에서 다음 스니펫을 onViewCreated 메서드에 추가하고 Slideandroidx.transition 버전을 가져옵니다.

ComposeFragment.kt

enterTransition = MaterialContainerTransform().apply {
   startView = requireActivity().findViewById(R.id.fab)
   endView = emailCardView
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   containerColor = requireContext().themeColor(R.attr.colorSurface)
   startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
   endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
   addTarget(R.id.email_card_view)
}

이전 컨테이너 변환을 구성하는 데 사용된 매개변수 외에도 startViewendView가 여기에서 수동으로 설정됩니다. transitionName 속성을 사용하여 Android 전환 시스템이 변환해야 하는 뷰를 알 수 있도록 하는 대신 필요할 때 수동으로 지정할 수 있습니다.

이제 앱을 다시 실행합니다. FAB가 작성 화면으로 변환되는 것을 확인할 수 있습니다 (이 단계 끝부분의 GIF 참고).

이전 단계와 마찬가지로, 전환이 삭제되고 ComposeFragment로 대체된 후 사라지지 않도록 전환을 HomeFragment에 추가해야 합니다.

NavController navigate 호출 전에 MainActivitynavigateToCompose 메서드에 아래 스니펫을 복사합니다.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialElevationScale(false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialElevationScale(true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

이 단계는 여기까지입니다. 다음과 같이 FAB에서 편지쓰기 화면으로 전환됩니다.

81b68391ac4b0a9.gif

6. 검색 아이콘에서 검색 뷰 페이지로의 공유 Z축 전환 추가

이 단계에서는 검색 아이콘에서 전체 화면검색 뷰로의 전환을 추가합니다. 이 탐색 변경과 관련된 영구 컨테이너가 없으므로 공유 Z축 전환을 사용하여 두 화면 사이의 공간 관계를 강화하고 앱 계층 구조에서 한 수준 위로 이동을 나타낼 수 있습니다.

코드를 더 추가하기 전에 앱을 실행하고 화면 오른쪽 하단의 검색 아이콘을 탭해보세요. 그러면 전환 없이 검색 뷰 화면이 표시됩니다.

499e1a677b4216bb.gif

먼저 MainActivity에서 navigateToSearch 메서드를 찾은 다음 NavController navigate 메서드 호출 앞에 다음 코드 스니펫을 추가하여 현재 프래그먼트의 종료 및 다시 들어가기 MaterialSharedAxis Z축 전환을 설정합니다.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

다음으로 SearchFragmentonCreate 메서드에 다음 코드 스니펫을 추가하여 진입 및 반환 MaterialSharedAxis 전환을 구성합니다.

SearchFragment.kt

enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

마지막으로 MaterialSharedAxis 전환이 계층 구조의 각 개별 뷰가 아닌 검색 화면 전체에 적용되도록 하려면 fragment_search.xmlLinearLayout를 전환 그룹으로 표시합니다.

fragment_search.xml

android:transitionGroup="true"

작업이 끝났습니다. 이제 앱을 다시 실행하여 검색 아이콘을 탭해보세요. 홈 화면 및 검색 뷰 화면이 Z축을 따라 동시에 깊이 페이드 아웃되면서 조정되어 두 화면 사이에 매끄러운 효과가 나타납니다.

e5c0b0a130e807db.gif

7. 편지함 페이지 간 페이드 스루 전환 추가

이 단계에서는 서로 다른 편지함 간 전환을 추가합니다. 공간 관계나 계층 관계를 강조하지 않으려고 하므로 페이드 스루를 사용하여 이메일 목록 간에 간단한 '전환'을 실행합니다.

코드를 더 추가하기 전에 앱을 실행하고 하단 앱 바에서 Reply 로고를 탭하여 편지함을 전환해보세요. 이메일 목록이 전환 없이 변경됩니다.

2c874c0a4588e8fb.gif

먼저 MainActivity에서 navigateToHome 메서드를 찾은 다음 NavController navigate 메서드 호출 앞에 다음 코드 스니펫을 추가하여 현재 프래그먼트의 종료 MaterialFadeThrough 전환을 설정합니다.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialFadeThrough().apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

그런 다음 HomeFragment을 엽니다. onCreate에서 프래그먼트의 enterTransitionMaterialFadeThrough의 새 인스턴스로 설정합니다.

HomeFragment.kt

enterTransition = MaterialFadeThrough().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

앱을 다시 실행합니다. 하단 탐색 창을 열고 편지함을 변경하면 현재 이메일 목록이 페이드 아웃되며 사라지고 새 목록이 페이드 인되며 나타납니다. 좋은 소식입니다.

f61dfd58ea7bd3fd.gif

8. 이메일 주소 칩에서 카드 뷰로의 컨테이너 변환 전환 추가

이 단계에서는 칩을 팝업 카드로 변환하는 전환을 추가합니다. 여기서 컨테이너 변환은 팝업에서 실행된 작업이 팝업이 발생한 칩에 영향을 미친다는 것을 사용자에게 알리는 데 사용됩니다.

코드를 추가하기 전에 Reply 앱을 실행하고 이메일을 클릭한 다음 '답장' FAB를 클릭한 후 수신자의 연락처 칩을 클릭해 보세요. 칩은 즉시 사라지며, 해당 연락처의 이메일 주소가 있는 카드가 애니메이션 없이 눈에 띄어야 합니다.

6200c682da2382d5.gif

이 단계에서는 ComposeFragment에서 작업합니다. ComposeFragment 레이아웃에는 이미 수신자 칩(기본적으로 표시됨)과 수신자 카드(기본적으로 표시되지 않음)가 추가되어 있습니다. 수신자 칩과 이 카드는 사이에 컨테이너 변환을 만들 두 개의 뷰입니다.

시작하려면 ComposeFragment를 열고 expandChip 메서드를 찾습니다. 이 메서드는 제공된 chip를 클릭하면 호출됩니다. recipientCardViewchip 표시 상태를 전환하는 줄 위에 다음 코드 스니펫을 추가합니다. 그러면 beginDelayedTransition를 통해 등록된 컨테이너 변환이 트리거됩니다.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = chip
   endView = binding.recipientCardView
   scrimColor = Color.TRANSPARENT
   endElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(binding.recipientCardView)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

이제 앱을 실행하면 칩이 수신자의 이메일 주소 카드로 변환됩니다. 다음으로, 카드가 다시 칩에 접히도록 돌아가기 전환을 구성해 보겠습니다.

ComposeFragmentcollapseChip 메서드에서 아래 코드 스니펫을 추가하여 카드를 다시 칩으로 접습니다.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = binding.recipientCardView
   endView = chip
   scrimColor = Color.TRANSPARENT
   startElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(chip)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

앱을 다시 실행합니다. 칩을 클릭하면 칩이 카드로 확장되고 카드를 클릭하면 카드가 다시 칩으로 접힙니다. 좋은 소식입니다.

e823b28e2890e05d.gif

9. 완료

MDC-Android 라이브러리는 100줄 미만의 Kotlin 코드와 몇 가지 기본 XML 마크업을 사용하여 Material Design 가이드라인을 준수하고 모든 Android 기기에서 일관되게 보이고 동작하는 기존 앱에서 멋진 전환을 만드는 데 도움이 되었습니다.

454a47ba96017a25.gif

다음 단계

머티리얼 모션 시스템에 관한 자세한 내용은 사양 및 전체 개발자 문서를 참고하세요. 앱에 머티리얼 전환을 추가해보세요.

머티리얼 모션을 사용해주셔서 감사합니다. 이 Codelab에 만족하셨길 바랍니다.

적절한 시간과 노력을 들여 이 Codelab을 완료할 수 있었습니다.

매우 동의함 동의함 보통 동의하지 않음 전혀 동의하지 않음

앞으로 머티리얼 모션 시스템을 계속 사용하고 싶습니다.

매우 동의함 동의함 보통 동의하지 않음 전혀 동의하지 않음