오늘날, 하나의 화면으로만 구성된 안드로이드 앱은 찾기 드뭅니다. 실제로 대부분의 앱은 사용자의 컨트롤로 여러 화면과 상호작용을 합니다.
이전에는 이러한 복잡한 화면의 이동 경로를 한 눈에 보면서 구성하는 쉬운 방법이 없었기 때문에 많은 코드를 작성해서 화면 전환을 해야했습니다.
이러한 비효율성을 해결하기 위해 Android에서는 네비게이션 컴포넌트
를 출시하였고, 이는 단순한 버튼 클릭부터, 복잡한 패턴에 이르는 여러 가지 탐색을 구현하도록 도와줍니다.
Safe Args
를 이용한 프래그먼트간 유형 안전성이 보장되는 데이터 전달 가능ViewModel
을 활용하여 UI 사이의 데이터 공유 가능네비게이션 컴포넌트를 사용하기 위해 앱의 build.gradle
에 종속 항목을 추가한다.
dependencies {
val nav_version = "2.4.1"
// Kotlin
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
}
화면 전환에 대한 action이나, 전달할 데이터 유형을 정의하려면 네비게이션 그래프 리소스 파일이 필요합니다.
프로젝트 도구 창의 res
폴더에서 마우스 우클릭 후 New
-Android Resource File
을 클릭하여 다음과 같이 설정합니다.
액티비티에 대상을 교체하기 위한 빈 컨테이너인, NavHostFragment
를 생성합니다.
<androidx.fragment.app.FragmentContainerView
android:id="@+id/newsNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/news_nav_graph" />
app:defaultNavHost="true"
속성을 사용하면 NavHostFragment
가 시스템 뒤로가기 버튼을 가로챕니다. 하나의 NavHost
만 기본으로 지정할 수 있습니다.
app:navGraph
속성은 NavHostFragment
를 탐색 그래프와 연결합니다. 탐색 그래프틑 사용자가 이동할 수 있는 NavHostFragment
의 모든 대상을 지정합니다.
아래 빨간색으로 체크한 아이콘을 클릭하여 목적지 프래그먼트를 추가합니다. 다음과 같이 프래그먼트간에 Action을 추가하여 이동 경로를 지정할 수 있습니다.
xml 코드로 본다면 다음과 같습니다. action
태그를 사용하여 다음 목적지를 지정할 수 있고, 화면 전환 애니메이션도 구성할 수 있습니다.
<fragment
android:id="@+id/breakingNewsFragment"
android:name="com.example.mvvmnewsapp.ui.fragments.BreakingNewsFragment"
android:label="BreakingNewsFragment" >
<action
android:id="@+id/action_breakingNewsFragment_to_articleNewsFragment"
app:destination="@id/articleNewsFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"/>
</fragment>
대상으로 이동하는 것은 NavController
객체를 사용하여 실행되며, 이 객체는 NavHost
내에서 앱 탐색을 관리합니다.
아래 코드는 NavHostFragment
에서 직접 NavController
를 검색하여 대상으로 이동하는 코드입니다. 메인 액티비티의 OnCreate
메서드 내에 작성합니다.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.newsNavHostFragment) as NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavigationView.setupWithNavController(navController)
프래그먼트에서 다음 경로를 이동할 때는 findNavController().navigate()
메서드를 사용하여 다음과 같이 액션과 Safe Args
를 사용한 번들 객체를 전달할 수도 있습니다.
newsAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
findNavController().navigate(
R.id.action_breakingNewsFragment_to_articleNewsFragment,
bundle
)
}
Safe Args
를 사용하려면 최상위 build.gradle
에 다음 class path
을 추가해야 합니다.
buildscript {
repositories {
google()
}
dependencies {
val nav_version = "2.4.1"
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
}
}
또한 앱 수준의 build.gradle
에 다음과 같은 플러그인도 추가해야합니다.
plugins {
id("androidx.navigation.safeargs.kotlin")
}
네비게이션 그래프 리소스 파일의 목적지 프래그먼트에서는 다음과 같이 수신 객체를 지정할 수 있습니다. 아래 코드는 article 객체를 수신 객체로 지정한 코드입니다.
<fragment
android:id="@+id/articleNewsFragment"
android:name="com.example.mvvmnewsapp.ui.fragments.ArticleNewsFragment"
android:label="ArticleNewsFragment" >
<argument
android:name="article"
app:argType="com.example.mvvmnewsapp.models.Article" />
</fragment>
프래그먼트 클래스에서는 -ktx
종속 항목을 사용할 때 다음과 같이 by navArgs()
속성 위임을 사용하여 인수에 액세스할 수도 있습니다.
다음 코드는 뉴스 기사의 번들 객체를 받아오고 이를 이용하는 코드입니다.
val args: ArticleNewsFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val article = args.article // article 객체를 받아온다.
binding.webView.apply {
webViewClient = WebViewClient()
loadUrl(article.url)
}
binding.fab.setOnClickListener {
viewModel.saveArticle(article) // DB 저장
Snackbar.make(view, "Article saved successfully", Snackbar.LENGTH_SHORT).show()
}
}