필자가 저번에 AAC Navigation을 사용하여 Fragment 간의 이동을 구현한 예제를 만들어 봤었다.
해당 예제에서는 간단한 버튼을 만들고, 버튼을 통해서 Fragment를 변경하도록 구현을 했었는데,
BottomNavigationView를 사용하여 Fragment 를 변경하고자 하니 정상적으로 동작이 되지 않았다.
따라서, AAC Navigation과 BottomNavigationView를 같이 사용하는 방법에 대해서 작성해볼까 한다.
글을 작서하기 앞서, AAC Navigtation에 대한 기본적인 사용 방법은 해당 게시글에서 확인하길 바란다.
[AAC] AAC Navigation 사용 실전 압축 정리
클린 아키텍처 예제를 작업 한 이후, 다양한 기술들을 적용시켜보고 있던 와중, Fragment 간의 이동을 아주 편리하게 도와주는 AAC Navigation 이 있길래 사용해보있다. AAC Navigation 에 대한 개념 정리글
heegs.tistory.com
우선,
Fragment를 생성하고, nav_graph를 생성하는 등
기본적인 AAC Navigtation을 사용하는 것과 마찬가지로 설정을 해둔다.
그 후, Fragment 간의 이동을 구현할 부분에서 BottomNavigationView를 사용한 Layout을 생성해 준다.
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavi"
android:layout_width="match_parent"
android:layout_height="57dp"
... />
그 다음, BottomNavigationView에서 보여줄 아이템들을 res/menu 폴더에 생성해준다.
menu 폴더가 없을 경우, res 폴더 밑에 menu 폴더를 생성 한 후 menu 아이템을 작성할 xml 파일을 만들면 된다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/bottom_item_first"
android:icon="@drawable/ic_launcher_foreground"
android:title="first" />
<item
android:id="@+id/bottom_item_second"
android:icon="@drawable/ic_launcher_foreground"
android:title="second" />
</menu>
icon은 마땅히 넣어둔 이미지가 없어서 기본적으로 가지고있는 launcher 이미지를 사용하도록 하였다.
Menu Item도 생성해 주었으면, BottomNavigationView에서 해당 아이템들을 클릭했을 때 Fragment를 변경하도록 구현해주면 된다.
우선,
BottomNavigationView에 대한 클릭 이벤트를 추가해 주도록 하자.
bottomNavi.setOnClickListener {
when (it.id) {
R.id.bottom_item_first -> {
it.findNavController().navigate(R.id.move_first_fragment)
}
R.id.bottom_item_second -> {
it.findNavController().navigate(R.id.move_second_fragment)
}
else -> {
Logger.d("onClick else ..")
}
}
}
이처럼 onClickListener를 사용하여 구현을 하게 되면,
정작 해당 아이템들을 클릭했을 때 이벤트를 이곳에서 받지 못한다.
따라서,
bottomNavi.setOnItemSelectedListener {
when (it.itemId) {
R.id.bottom_item_first -> {
true
}
R.id.bottom_item_second -> {
true
}
else -> {
false
}
}
}
이처럼 setOnItemSelectListener를 사용하여 클릭 이벤트를 잡아주어야 한다.
하지만,
setOnItemSelectListener를 사용하게 되면 기존의 onClickListener를 사용했을 때 처럼
it.findNavController().navigate()
를 사용할 수 없다.
it에는 View, Activity, Fragment가 들어갈 수 있는데 setOnItemSelectListener에서의 it은 MenuItem이기 때문이다.
따라서, 다른 방법을 통해 이동할 수 있는지 확인해 보았다.
Navigation.createNavigateOnClickListener(R.id.move_first_fragment)
와 같이 선언하여 이동이 가능하다고 한다.
nav_graph의 Action에 정의된 ID 값으로 리스너를 반환하여 이동시키는 방법이라고 하는데,
해당 라인만 추가해서는 정상적으로 동작하지 않았다.
다른 추가적인 작업이 필요할 수 있고 필자가 잘못 작업하여 동작이 되지 않았을 수 있지만,
여러모로 구글링을 해보고 적용해 보아도 정상적으로 동작하지 않았다.
따라서, 필자는 다시한번 AAC Navigation 관련한 Developers 문서를 확인해 보았는데
그 곳에서 해결 방안을 찾을 수 있었다.
(역시 공식 문서에는 없는게 없는것 같다.)
공식문서를 확인하면 다음과 같이 정의되어 있다.
NavigationUI 에는 연결된 대상을 호스팅하는 NavController와 함께 MenuItem을 받는 도우미 메서드 onNavDestinationSelected()가 포함되어 있습니다.
MenuItem의 id가 대상의 id와 일치하면 NavController가 그 대상으로 이동할 수 있습니다.
즉, MenuItem을 사용하는 setOnItemSelectListener에서는 onNavDestinationSelected()를 사용하면 된다는 뜻이다.
또한, BottomNavigation 관련한 부분에는 다음과 같이 정의되어 있다.
NavigationUI는 하단 탐색도 처리할 수 있습니다.
사용자가 메뉴 항목을 선택하면 NavController는 onNavDestinationSelected()를 호출하고 하단 탐색 메뉴에서 선택된 항목을 자동으로 업데이트합니다.
즉, NavController와 onNavDestinationSelected를 사용하여 자동으로 fragment를 변경할 수 있다는 것이다.
그렇다면, 사용하는 방법에 대해서 확인해보자.
Developers 문서의 스니펫에서는 다음과 같이 구현되어 있다.
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)
...
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
findViewById<BottomNavigationView>(R.id.bottom_nav)
.setupWithNavController(navController)
}
onCreate 시 FragmentManager를 사용하여 navHostFragment를 구하고,
navHostFragment를 사용하여 navController를 구하여 해당 BottomNavigationView에 controller를 설정해주면 되는 것 같다.
필자는 해당 부분을 따로 함수로 빼내고, onCreate에서 호출하도록 구현하였다.
private fun initNavigation() {
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
findViewById<BottomNavigationView>(R.id.bottomNavi).setupWithNavController(navController)
bottomNavi.setOnItemSelectedListener {
Logger.d("bottomNavi setOnItemSelectedListener .. $it\n${it.itemId}\n${it.actionView}")
when (it.itemId) {
R.id.first_fragment -> {
}
R.id.second_fragment -> {
}
}
it.onNavDestinationSelected(navController)
}
}
우선, setOnItemSelectListener에서 when절을 통해 분기처리를 하지 않아도 상관 없다.
it.onNavDestinationSelected(navController)
을 통하여 클릭된 메뉴에 따라 자동적으로 Fragment를 변경시켜주기 때문이다.
하지만, Fragment를 변경할 때 별도의 작업이 필요할 경우가 있을 것 같아서 임시로 when 절을 작성해 주었다.
위 처럼 controller를 설정을 해두고,
setOnitemSelectListener 구문에 it.onNavDestinationSelected()만 호출하도록 구현 한 다음 실행을 해보면
정상적으로 원하는대로 Fragment가 변경되는 것을 확인 할 수 있다.
클릭 이벤트를 받을 수 있을 때와 없을 때 Navigation을 사용해 Fragment를 이동하는 동작이 다르게 구현될 것이라고는 생각을 못했었다.
역시 어떠한 것을 적용하기 앞서, 구글링을 통해 사용 방법을 확인하는 것 보다 앞서 Developers 문서를 통해서 찾아보는 것이 좋을 것 같다.
기존에 버튼을 클릭했을 때 Fragment를 이동하는 방식과 BottomNavigationView를 사용하여 Fragment를 이동하는 방식 두 가지를 사용한다면, 실 구축시에 기본적인 UI 구현에는 큰 문제가 없을 것 같다.
Developers 문서를 확인해보니 다양한 사용 방법이 나와있는데, 추후 필요할 때 한번 더 정독을 한 후 작업을 진행해야 할 것 같다.
해당 게시글에 작성한 내용이 작성되어 있는 Developers 문서 확인이 필요하다면, 다음 링크를 확인하길 바란다.
https://developer.android.com/guide/navigation/navigation-ui?hl=ko#bottom_navigation
NavigationUI로 UI 구성요소 업데이트 | Android 개발자 | Android Developers
NavigationUI로 UI 구성요소 업데이트 탐색 구성요소에는 NavigationUI 클래스가 포함되어 있습니다. 이 클래스에는 상단 앱 바, 탐색 창 및 하단 탐색으로 탐색을 관리하는 정적 메서드가 포함되어 있
developer.android.com
'Android > AAC' 카테고리의 다른 글
[Android] AAC (Android Architecture Components) 란 ? (Feat. ViewModel) (0) | 2022.05.31 |
---|---|
[Android] Jetpack DataStore 실전 압축 정리 (0) | 2022.02.17 |
[Android] AAC Navigation 사용 실전 압축 정리 (0) | 2022.02.14 |
[Android] 데이터 바인딩 어댑터 (Data Binding Adapter) 사용 방법 (0) | 2022.02.07 |
[Android] Room 라이브러리 (0) | 2020.06.22 |