마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

safe args를 이용한 프래그먼트 교체 시 bottomnavigationview 오작동 질문

0 추천

안녕하세요. BottomNavigationView와 main_include_drawer를 둘 다 사용하는 어플을 개발하고 있습니다. BottomNavigationView가 메인이고 drawer에서 메뉴를 클릭하면 아래 코드와 같이 safe args를 사용하여 프래그먼트를 교체하고 있습니다.

val action =
    PostFragmentDirections.actionGlobalNavigationPost("${it.title}")
navController.navigate(action)

 

drawer에서 메뉴를 클릭하면 Post 프래그먼트로 교체되지만 BottomNavigationView가 비정상 동작하는 것을 발견했습니다.

예를들어 Home프래그먼트에서 drawer를 통한 프래그먼트 교체시, BottomNavigationView의 Dasgboard와 MyPage 버튼은 정상적으로 동작하지만 Home 버튼은 Home 프래그먼트가 아닌 교체된 Post 프래그먼트로 변경됩니다. 

어떻게 BottomNavigationView 동작을 원래대로 즉 Post 프래그먼트가 아닌 교체되기 전 프래그먼트를 불러오도록 만들 수 있을까요?

aqper (230 포인트) 님이 2022년 2월 17일 질문

2개의 답변

+1 추천
 
채택된 답변
질문만으로 원인을 추측하기에는 좀 무리가 있지만,  Navigation Drawer와 NavController를 설정하는 부분이 완전하지 않을 걸로 보입니다. 아래 링크에 가셔서 필요한 설정이 되었는지 꼼꼼히 확인해 보세요.

https://developer.android.com/guide/navigation/navigation-ui#add_a_navigation_drawer

잘 안되시면, 어떻게 네비게이션을 설정하셨는지 navigation graph와 관련 코드를 올리시면 좋을 것 같습니다.
spark (228,010 포인트) 님이 2022년 2월 18일 답변
aqper님이 2022년 2월 19일 채택됨
네비게이션은  BottomNavigationView에만 등록하고 Drawer의 경우는 동적으로 메뉴를 api를 통해 데이터를 얻어오고 이를 바탕으로 생성하는 식이라 setOnMenuItemClickListener 내부에 본문의 코드를 넣어 프레그먼트를 변경하는 식으로 구성됬습니다. 아래 코드는 BottomNavigationView에 네비게이션을 추가하는 코드입니다.

val navView: BottomNavigationView = binding.aMain.navView

navController =     (supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment).navController

navView.setupWithNavController(navController)

혹시 bottomnavigationview와 drawerview를 동시에 사용하려면FragmentContainerView를 2개 사용하여서 각각 다른 네비게이션을 등록해야하는데 제가 생각을 잘못한 걸까요?
BottomNavigationView에 있는 메뉴와 똑같은 메뉴가 NavigationDrawer에 있다면, 둘의 id가 똑같이 navigation graph에 있는 것과 같아야 합니다. 그래야 Navigation Component에서 제공하는 백스택, 뷰복구 등을 덤으로 사용하실 수가 있습니다. 그렇게 하실 수 없다면 코드를 통해 그 부분들을 처리하셔야 합니다.
" bottomnavigationview와 drawerview를 동시에 사용하려면FragmentContainerView를 2개 사용하여서" ->. 이 부분은 잘못 된 것 같습니다. 웬만한 경우라면 1개만 필요합니다.
메뉴가 똑같은 구성이 아니라 코드를 통해 처리해야겠네요. 아직 해결하진 못했지만 많은 도움이 됬습니다 감사합니다.
덕분에 bottomnavigationview의 setOnItemSelectedListener를 커스텀하여 처리하는데 성공했습니다. setOnItemSelectedListener 실행 시 navController를 통해 프레그먼트를 옮기는 방식으로 하여 야매로 해결한 것 같지만 제가 부족하여 이외의 방식은 모르겠네요 ㅋㅋ;;

덕분에 해결할 수 있었습니다. 감사합니다.

아래는 해결한 코드입니다.
binding.aMain.navView.run {
            setOnItemSelectedListener { item ->
                var action: NavDirections? = null
                when (item.itemId) {
                    R.id.navigation_home -> {
                        action = HomeFragmentDirections.actionGlobalNavigationHome()
                    }
                    R.id.navigation_dashboard -> {
                        action = DashboardFragmentDirections.actionGlobalNavigationDashboard()
                    }
                    R.id.navigation_mypage -> {
                        action = MyPageFragmentDirections.actionGlobalNavigationMypage()
                    }
                }
                if (action != null)
                    navController.navigate(action)
                true
            }
            selectedItemId = R.id.navigation_home
        }
+1 추천

참고로, 코틀린 코드를 조금 읽기 더 좋게 만들면,

binding.aMain.navView.apply {
    setOnItemSelectedListener { item ->
        val action: NavDirections = when (item.itemId) {
            R.id.navigation_home -> HomeFragmentDirections.actionGlobalNavigationHome()
            R.id.navigation_dashboard -> DashboardFragmentDirections.actionGlobalNavigationDashboard()
            R.id.navigation_mypage -> MyPageFragmentDirections.actionGlobalNavigationMypage()
            else -> return true
        }
               
        navController.navigate(action)
        true
     }
            
     selectedItemId = R.id.navigation_home
}

위의 코드는 맵핑 테이블을 써서 좀 더 정확하고 간결하게 변경할 수 있습니다.

enum class NavigationDrawerItemType(val naviId, val direction: NavDirections) {
     HOME(R.id.navigation_home, HomeFragmentDirections.actionGlobalNavigationHome()),
     DASHBOARD(R.id.navigation_dashboard, DashboardFragmentDirections.actionGlobalNavigationDashboard()),
     MY_PAGE(R.id.navigation_mypage, MyPageFragmentDirections.actionGlobalNavigationMypage());
 
     companion object {
        fun from(navId: Int): NavigationDrawerItemType? {
            return NavigationDrawerItemType.values().find { item -> item.navid == navId }
        }
     }
}


binding.aMain.navView.apply {
    setOnItemSelectedListener { item ->
        val action: NavDirections = NavigationDrawerItemType.from(item.itemId) ?: return true
        navController.navigate(action)
        true
     }
            
     selectedItemId = NavigationDrawerItemType.Home.navId
}

 

spark (228,010 포인트) 님이 2022년 2월 18일 답변
코드가 훨씬 간결해지네요. 덕분에 계속 배우네요. 감사합니다. ㅎㅎ
...