안녕하세요
이번 포스팅은 Jetpack 구성 요소 중 Navigation에 대해 정리해보려 합니다.
Navigation
Navigation은 위의 그림과 같이 서로 다른 UI의 이동을 관리하는 요소라고 할 수 있습니다. Android Jetpack의 Navigation은 특히 App bar, Navigation Drawer 등과 같은 간단한 클릭으로 Navigation을 구현할 수 있게 해줍니다.
구성 요소
- Navigation graph : 모든 Navigation과 연관된 정보를 가지고 있는 XML. Destinations라고 불리는 앱의 개별 콘텐츠 공간으로 사용자가 앱에서 이동할 수 있는 경로 등을 포함합니다.
- NavHost : Navigation graph로 부터 Destinations에 표시할 빈 Container. Navigation은 기본적으로 Fragment Destinations을 출력할 기본 NavHost인 NavHostFragment이 포함되어 있습니다.
- NavController : NavHost 안에 Navigation을 관리하는 객체. 사용자가 앱 화면을 이동할 때 콘텐츠 변경을 관리합니다.
특정 경로를 탐색하거나, 특정 목적지 이동을 위해 NavController에 알립니다. 이후, NavHost에 적절한 목적지를 보여줍니다.
장점
- Fragment 트랜젝션 처리
- 기본적으로 앞 혹은 뒤로의 동작을 처리
- 애니메이션과 트랜젝션에 대한 표준화된 리소스
- deep linking 처리 및 구현
- 최소한의 작업을 Navigation UI 패턴을 사용할 수 있음(Naviagion Drawer, Bottom Navigation)
- Safe Args : 대상 간 데이터를 탐색하고 전달할 때 타입 안전성을 제공하는 Gradle Plugin
- ViewModel 지원
시작하기
Xml로 NavHostFragment 추가
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
.../>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
코드 설명
- "android:name" 속성에는 NavHost가 구현된 클래스 이름이 작성됩니다.
- "app:navGraph" 속성은 Navigation Graph를 가진 NavHostFragment와 연결됩니다.
- "app:defaultNavHost="true"" 속성은 NavHostFragment가 시스템 취소 버튼에 반응할 수 있게 합니다.
하나의 NavHost만이 기본값일 수 있습니다. 동일한 레이아웃에 여러개의 NavHost가 있다면 기본 NavHost를 정해야합니다.
Navigation Graph로 Destination 추가
Navigation Editor로 새로운 Destination를 추가할 수 있습니다.
- New Destination 아이콘 클릭후, Create new destination 항목을 클릭합니다.
- 보이는 New Android Component 화면에서, Fragment를 생성합니다.
Navigation Editor 생성화면
Destination 세부 사항
- Type 필드는 Destination이 어떤 Component로 구현되었는지 표기합니다. (Fragment, Activity 혹은 Custom 클래스)
- Label 필드는 Destination이 사용자가 읽을 수 있는 이름을 나타내며, UI에 표시될 수 있습니다.
- ID 필드는 코드에서 Destination을 가리키기 위해 사용되는 ID 입니다.
- Class 필드는 Destination과 연관된 클래스의 이름을 보여줍니다. 드롭다운을 클릭하여 연결된 클래스를 다른 Destination 타입으로 변경할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="@string/label_blank"
tools:layout="@layout/fragment_blank" />
</navigation>
시작 Destination 설계
시작 Destination은 앱을 실행하고 첫번째로 보이는 화면이고, 앱을 종료할 때 보이는 마지막 화면입니다.
Navigation 에디터에서는 집 모양 아이콘으로 시작 Destination을 지정할 수 있습니다.
Destination 연결
Destination 끼리 연결되는 것을 Action이라고 합니다. Action은 화살표로 표기되고, Destination 간의 연결 혹은 어느곳에서나 특정 화면으로 이동할 수 있게 할 수 있습니다.
Action은 Navigation Editor(XML)로 작성하거나 코드로도 작성할 수 있습니다
Destination으로 이동
Destination으로 이동하기 위해서는 NavHost 내에 앱 이동을 관리하는 NavController를 사용한다. NavHost는 각 고유의 NavController를 가지고 있는데, 아래의 API를 통해서 NavController를 검색할 수 있다.
Kotlin:
Java:
- NavHostFragment.findNavController(Fragment)
- Navigation.findNavController(Activity, @IdRes int viewId)
- Navigation.findNavController(View)
FragmentContainerViewNavHostFragment를 생성하거나, FragementTransaction을 통해 Activity에 NavHostFragment를 수동으로 추가한다면, Navigation.findNavController(Activity, @IdRes int)를 통해 Activity의 onCreate()안에서 NavController를 검색시도한다면 실패할 것입니다.
위의 방법보다는, NavHostFragment로 부터 바로 NavController를 검색해야합니다.
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Safe Args를 사용하여 Type-Safety 보장
gradle 설정
buildscript {
repositories {
google()
}
dependencies {
val nav_version = "2.5.3"
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
}
}
Java, Kotlin 혼합 plugin
plugins {
id("androidx.navigation.safeargs")
}
Kotlin 용 plugin
plugins {
id("androidx.navigation.safeargs.kotlin")
}
* Android X로의 마이그레이션에 따라 gradle.properties에 android.useAndroidX=true를 추가해야합니다.
SafeArgs를 활성화한 후, plugin은 정의된 각각의 액션과 관련된 클래스와 메소드를 포함한 코드를 생성합니다.
또한, 각각의 액션과 관련되어, SafeArgs는 작업의 시작이 되는 시작 Destination에 대한 클래스도 생성하는데,
생성된 클래스 이름은 "Directions"가 붙습니다.
예시) SpecifyAmountFragment에서 생성된 클래스는 SpecifyAmountFragmentDirections
생성된 클래스에는 Destination에 정의된 액션을 위한 정적 메소드도 포함되어있습니다. 이 메소드는 정의된 파라미터를 인수로 사용하고, navigate()에 전달가능한 NavDirections를 반환합니다.
예시
시작 Destination : SpecifyAmountFragment수신 Destination : ConfirmationFragment
SafeArgs는 NavDirections 개체를 반환하는 actionSpecifyAmountFragmentToConfirmationFragment()를 사용하여 SpecifyAmountFragmentDirections 클래스를 생성
반환된 NavDirections은 navigate()에 직접 전달 가능
override fun onClick(view: View) {
val action =
SpecifyAmountFragmentDirections
.actionSpecifyAmountFragmentToConfirmationFragment()
view.findNavController().navigate(action)
}
'DEV > Android' 카테고리의 다른 글
[TIL-230512] Google Map Api 적용하기 (2) | 2023.05.12 |
---|---|
[Android] Jetpack - Paging - 1 (0) | 2023.04.11 |
[Android] Jetpack - LiveData - 2 (4) | 2023.03.29 |
[Android] Jetpack - LiveData - 1 (0) | 2023.03.27 |
[Android] Jetpack - Lifecycle - 2 (0) | 2023.03.21 |