[Android AAC] 네비게이션 컴포넌트

0

Android

목록 보기
7/16
post-thumbnail

개요

오늘날, 하나의 화면으로만 구성된 안드로이드 앱은 찾기 드뭅니다. 실제로 대부분의 앱은 사용자의 컨트롤로 여러 화면과 상호작용을 합니다.

이전에는 이러한 복잡한 화면의 이동 경로를 한 눈에 보면서 구성하는 쉬운 방법이 없었기 때문에 많은 코드를 작성해서 화면 전환을 해야했습니다.

이러한 비효율성을 해결하기 위해 Android에서는 네비게이션 컴포넌트를 출시하였고, 이는 단순한 버튼 클릭부터, 복잡한 패턴에 이르는 여러 가지 탐색을 구현하도록 도와줍니다.

네비게이션 컴포넌트의 장점

  • 프래그먼트의 트랜잭션 처리
  • '위로', '뒤로' 작업을 올바르게 처리
  • 애니메이션과 전환에 표준화된 리소스 제공
  • 딥 링크 구현 및 처리
  • Safe Args를 이용한 프래그먼트간 유형 안전성이 보장되는 데이터 전달 가능
  • ViewModel을 활용하여 UI 사이의 데이터 공유 가능

네비게이션 컴포넌트 시작하기

1. 종속 항목 추가

네비게이션 컴포넌트를 사용하기 위해 앱의 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")
}

2. 네비게이션 그래프 리소스 파일 생성

화면 전환에 대한 action이나, 전달할 데이터 유형을 정의하려면 네비게이션 그래프 리소스 파일이 필요합니다.
프로젝트 도구 창의 res 폴더에서 마우스 우클릭 후 New-Android Resource File 을 클릭하여 다음과 같이 설정합니다.

3. 네비게이션 호스트 추가

액티비티에 대상을 교체하기 위한 빈 컨테이너인, 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의 모든 대상을 지정합니다.

4. 네비게이션 목적지 추가하기

아래 빨간색으로 체크한 아이콘을 클릭하여 목적지 프래그먼트를 추가합니다. 다음과 같이 프래그먼트간에 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 사용

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()
    }
}

0개의 댓글