Android Jetpack

Navigation으로 UI의 화면전환 구현하기

wdadaww 2023. 1. 25. 00:49
  • Jetpack Navigation이란?

Android Jetpack의 Navigation은 UI 전환을 쉽게 구현하는데 도와주는 라이브러리입니다. 개발자가 정의한 UI Graph를 기반으로 화면을 쉽게 전환하고, 유지보수가 매우 쉬워집니다.

 

  • Jetpack Navigation의 도입

기존에는 앱에서 프래그먼트를 전환하려면  supportFrgemnetManager로 인스턴스를 반환한다음에 replace ,add 를 통해 프래그먼트를 교체하고 commit으로 실행햇습니다.


 

출처:탐색 구성요소 시작하기  |  Android 개발자  |  Android Developers

 

탐색 구성요소 시작하기  |  Android 개발자  |  Android Developers

탐색 구성요소 시작하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 주제는 탐색 구성요소를 설정하고 사용하는 방법을 설명합니다. 탐색 구성요소

developer.android.com


 

  • 먼저 build.gradle에 Navigation을 사용하기위해 추가한다.
    //Navigation
    implementation "androidx.navigation:navigation-ui-ktx:2.5.3"
    implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"

  • Navigation의 3대 컴포넌트
  • Navigation graph
  • Navigation host
  • Navigation controller 

 기존에 했던 책 검색 앱만들기를 통해 네비게이션(Navigation)의   기본적인 사용 방법을 알아보겟습니다.


  • res/android resource file를 만들어주고 리소스타입을 navigation으로 지정한다음 생성해줍니다.

 

  • Navigation Editor
  • Navigation Graph
  • 아래 그림처럼 화면들이 어떻게 연결되어 있는지 시각적으로 보여주는 XML 리소스 파일. 그러니까 사용자가 앱에서 이동할 수 있는 경로를 그릴수있다. ( 경로를 안정해줘서 아직 화살표 표시는안되잇다.)

 

1. search -> favoirte -> setting 순으로  프래그먼트를 각각 추가해주면된다

 

2. 주의해야할점은 Menu의 <Item>의 id와 bookSearch_ Nav_Graph의 Destination(<fragment>)의 id가 같아야된다.

 

3. Navigation UI를 사용하여  아래의 Menu, Drawers, toolbar등의 UI들의 Action을 직접 구현하지 않고,

간단하게 연결하여 사용이 가능하다. 

  • Toolbar
  • CollapsingToolbarLayout
  • ActionBar
  • DrawerLayout
  • BottomNavigationView

 

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/booksearch_nav_graph"
    app:startDestination="@id/fragment_search">
    <fragment
        android:id="@+id/fragment_search"
        android:name="com.example.kakaobook.ui.view.ui.view.SearchFragment"
        android:label="@string/search"
        tools:layout="@layout/fragment_search" />
    <fragment
        android:id="@+id/fragment_favorite"
        android:name="com.example.kakaobook.ui.view.ui.view.FavoriteFragment"
        android:label="@string/favorite"
        tools:layout="@layout/fragment_favorite" />
    <fragment
        android:id="@+id/fragment_settings"
        android:name="com.example.kakaobook.ui.view.ui.view.SettingsFragment"
        android:label="@string/settings"
        tools:layout="@layout/fragment_settings" />
</navigation>

  • 액티비티 안에 NavHost를 추가해주자.
  • NavHost-> navigation graph 내의 Fragment가 표시되는 빈 컨테이너.
<?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=".ui.view.ui.view.MainActivity">

    <FrameLayout
        android:id="@+id/FrameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/bottom_navigation_memu"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/booksearch_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/booksearch_nav_graph" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation_memu"
        android:layout_width="0dp"
        android:layout_height="50dp"
        app:itemIconTint="@color/white"
        app:itemTextColor="@color/purple_200"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

  • Navigation Host

  • android:name ->속성은 NavHost 구현의 클래스 이름을 포함합니다.
  • app:nav:Graph -> 속성은 NavHostFragment를 탐색 그래프와 연결합니다. 탐색 그래프는 사용자가 이동할 수 있는 이 NavHostFragment의 모든 대상을 지정합니다.
  • app:defaultNavHost="true" -> 속성을 사용하면 NavHostFragment가 시스템 뒤로 버튼을 가로챕니다. 하나의 NavHost만 기본값으로 지정할 수 있습니다. 동일한 레이아웃에 여러 호스트가 있다면(예: 창이 2개인 레이아웃) 한 호스트만 기본 NavHost로 지정해야 합니다.

  • Navigation Controller- 화면 전환을 수행하는 컨트롤러.

위를 참조해서 코드를 작성햇습니다.

private fun setupJetpackNavigation() {
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.booksearch_nav_host_fragment) as NavHostFragment
    navController = navHostFragment.navController
    binding.bottomNavigationMemu.setupWithNavController(navController)

}

navController 객체를얻어   setupwithnavcontroller 통해서  bottomNavigationMenu를 navcontroller랑 연결을해줘서

프래그먼트 전환을 하게됩니다.

 

  • 전체코드
package com.example.kakaobook.ui.view.ui.view

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.example.kakaobook.R
import com.example.kakaobook.databinding.ActivityMainBinding
import com.example.kakaobook.ui.view.repository.BookSearchRepositoryImpl
import com.example.kakaobook.ui.view.ui.view.viewmodel.BookSearchViewModel
import com.example.kakaobook.ui.view.ui.view.viewmodel.BookSearchViewModelProvideFactory


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    lateinit var bookSearchViewModel: BookSearchViewModel
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        setupJetpackNavigation()

        val bookSearchRepository = BookSearchRepositoryImpl()
        val factory = BookSearchViewModelProvideFactory(bookSearchRepository)

        //뷰모델 적용
        bookSearchViewModel = ViewModelProvider(this, factory)[BookSearchViewModel::class.java]
    }

    private fun setupJetpackNavigation() {
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.booksearch_nav_host_fragment) as NavHostFragment
        navController=  navHostFragment.navController
        binding.bottomNavigationMemu.setupWithNavController(navController)

    }

}




  • AppBarConfiguration

현재 보여지고 있는 화면의 Label을 AppBar에 보여주고 싶을 수 있습니다. AppBarConfiguration을 이용하면 네비게이션 그래프에 정의된 Label을 AppBar에 출력할 수 있습니다. 더불어 AppBar에 뒤로가기(<-) 버튼까지 보여줍니다. 뒤로가기 버튼은 startDestination로 정의된 처음 화면이 아닐 때만 보여줍니다.

-> AppBarConfiguration는 navController의 graph 변수를 인자로 넘겨주어 생성합니다.

그러고 setupActionBarWithNavController는 두 객체를 AppBar에 적용합니다.

-> AppBar에 생성되는 뒤로가기 버튼을 눌렀을 때, 뒤로 이동하려면 onSupportNavigateUp를 오버라이드해야 합니다.

 

출처: NavigationUI로 UI 구성요소 업데이트  |  Android 개발자  |  Android Developers

 

NavigationUI로 UI 구성요소 업데이트  |  Android 개발자  |  Android Developers

NavigationUI로 UI 구성요소 업데이트 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 탐색 구성요소에는 NavigationUI 클래스가 포함되어 있습니다. 이 클래스에는

developer.android.com


  • 전체코드
package com.example.kakaobook.ui.view.ui.view

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.kakaobook.R
import com.example.kakaobook.databinding.ActivityMainBinding
import com.example.kakaobook.ui.view.repository.BookSearchRepositoryImpl
import com.example.kakaobook.ui.view.ui.view.viewmodel.BookSearchViewModel
import com.example.kakaobook.ui.view.ui.view.viewmodel.BookSearchViewModelProvideFactory


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    lateinit var bookSearchViewModel: BookSearchViewModel
    private lateinit var navController: NavController
    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setupJetpackNavigation()

        val bookSearchRepository = BookSearchRepositoryImpl()
        val factory = BookSearchViewModelProvideFactory(bookSearchRepository)

        //뷰모델 적용
        bookSearchViewModel = ViewModelProvider(this, factory)[BookSearchViewModel::class.java]
    }
       
    private fun setupJetpackNavigation() {
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.booksearch_nav_host_fragment) as NavHostFragment
        navController=  navHostFragment.navController
        binding.bottomNavigationMemu.setupWithNavController(navController)
        
        appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController,appBarConfiguration)
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
}

  •        앱바에 뒤로가기 버튼을 누르면  처음화면으로 이동하는걸 볼수있었다.