한번씩은 안드로이드 앱 개발을 하면서 activity 또는 fragment간의 transition이 늘어나고 transition간의 애니메이션을 추가하면서 코드가 복잡해져 코드가 꼬이고 불편했던 적이 있을 것이다. 이것을 더욱 쉽고 편리하게 해주는 것이 오늘 소개할 Jetpack Navigation이다.
Goolgle Developer 공식 사이트에서는 Navigation을 다음과 같이 정의하고 있다.
Navigation은 Android 애플리케이션 내에서 '대상' 사이를 탐색하는 프레임워크로, 대상이 Fragment, Activity 또는 기타 구성요소로 구현되었는지에 관계없이 일관된 API를 제공합니다.
즉, 화면 이동을 보다 쉽고 편리하게 해주는 Jetpack의 라이브러이이다.
Jetpack Navigation은 총 3가지의 구성으로 이루어져있다.
Navigation graph는 새로운 xml resource으로 사용하고자하는 화면들의 모든 정보를 한눈에 볼 수 있는 xml 파일이다. 이곳에서 화면 이동 destination, animation, arguement 등 다양한 정보를 수정하고 만들 수 있다.
NavHost는 Navigation 그래프에 있는 fragment destinations을 전환해주는 역할을 한다. 간단하게 fragment 네비게이션을 위한 화면에 빈 위젯 또는 빈창이라고 생각하면 됩니다.
// Command to navigate to action_fragment1_to_fragment2
findNavController().navigate(R.id.action_fragment1_to_fragment2)
NavController는 NavHost에서 fragment 스왑을 트리거하는 기능입니다.
res에서 new -> Android Resource File -> resource type에서 Navigation를 선택하고 생성하면 res에 navigation 폴더안에 navigation graph가 생성된다.
생성된 navigation graph xml에서 들어가면 화면을 구성할 수 있는 부분이 있다. 여기서 상단에 플러스 모양 아이콘을 클릭하면 navigation graph에 추가하고 싶은 화면들을 추가할 수 있다.
원하는 화면들을 추가하면 다음그림과 같이 해당 화면들이 추가된것을 확인할 수 있다.
여기서 원한는 fragment를 클릭하면 다른 fragment로 화살표 모양의 직선을 그릴 수 있다. 이 직선은 action이라고 하는데 이것이 해당 화면의 이동 방향을 알려주는 기능을 하고 있다. 단 화살표만으로 화면 이동이 가능한것이 아니기 때문에 따로 navHost 와 controller를 사용해야한다.
해당 navigation graph xml의 코드는 다음과 같다.
<?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/nav_graph"
app:startDestination="@id/fragment1">
<fragment
android:id="@+id/fragment1"
android:name="com.mobinity.registerusingnavgraph.Fragment1"
android:label="fragment_1"
tools:layout="@layout/fragment_1" >
<action
android:id="@+id/action_fragment1_to_fragment2"
app:destination="@id/fragment2" />
</fragment>
<fragment
android:id="@+id/fragment2"
android:name="com.mobinity.registerusingnavgraph.Fragment2"
android:label="fragment_2"
tools:layout="@layout/fragment_2" >
<action
android:id="@+id/action_fragment2_to_fragment3"
app:destination="@id/fragment3" />
</fragment>
<fragment
android:id="@+id/fragment3"
android:name="com.mobinity.registerusingnavgraph.Fragment3"
android:label="fragment_3"
tools:layout="@layout/fragment_3" >
<action
android:id="@+id/action_fragment3_to_fragment4"
app:destination="@id/fragment4" />
</fragment>
</navigation>
코드에서 각 fragment를 보면 fragment안에 action이라는 것을 볼 수 있다. 이 action이 각 fragment의 destination을 설정해준다. action출발_to도착 이라고 생각하면 된다. 하지만 action을 설정한다고 바로 화면 이동이 활성이 되는것이 아니기 때문에 추가적인 작업이 필요하다.
이제 해당 activity에서 fragment를 보여줄 뷰를 추가해야한다.원하는 activity 레이아웃에서 fragment view를 추가해 주면된다.
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
navGraph 와 defaultNavHost 설정은 필수적으로 해줘야 한다.
해당 fragment 뷰가 있는 activity에서 설정해주면 된다. MainActivity에 fragment 뷰가 있다고 가정해보자. 그럼 다음과 같이 navigationController를 설정해주면 된다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
}
}
Activity에서 navigationController를 만들고, 이를 활용해 navigate를 수행해주면 된다.
이제는 각 fragment로 가서 버튼을 통해 화면 이동을 하는 법을 해보자
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val navController = Navigation.findNavController(view)
btn.setOnClickListener {
navController.navigate(R.id.action_fragment1_to_fragment2)
}
}
NavController를 선언하고 onViewCreated에서 받아온 view를 통해 navController를 정의한다.
마지막으로 버튼을 클릭시 navController의 navigate를 해당 action으로 설정해준다. 그러면 버튼을 클릭시 해당 action를 통해 fragment2로 화면이 이동된다.