Navigation으로 UI의 화면전환 구현하기
- 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()
}
}
- 앱바에 뒤로가기 버튼을 누르면 처음화면으로 이동하는걸 볼수있었다.