새 탐색 구성 요소를 사용하려고합니다. navController와 함께 BottomNavigationView를 사용합니다. NavigationUI.setupWithNavController (bottomNavigation, navController)
그러나 프래그먼트를 전환 할 때 이전에 사용 된 경우에도 매번 파괴 / 생성됩니다.
BottomNavigationView에 대한 주요 프래그먼트 링크를 유지하는 방법이 있습니까?
새 탐색 구성 요소를 사용하려고합니다. navController와 함께 BottomNavigationView를 사용합니다. NavigationUI.setupWithNavController (bottomNavigation, navController)
그러나 프래그먼트를 전환 할 때 이전에 사용 된 경우에도 매번 파괴 / 생성됩니다.
BottomNavigationView에 대한 주요 프래그먼트 링크를 유지하는 방법이 있습니까?
답변:
이 시도.
사용자 지정 탐색기를 만듭니다.
@Navigator.Name("custom_fragment") // Use as custom tag at navigation.xml
class CustomNavigator(
private val context: Context,
private val manager: FragmentManager,
private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {
override fun navigate(destination: Destination, args: Bundle?, navOptions: NavOptions?) {
val tag = destination.id.toString()
val transaction = manager.beginTransaction()
val currentFragment = manager.primaryNavigationFragment
if (currentFragment != null) {
transaction.detach(currentFragment)
}
var fragment = manager.findFragmentByTag(tag)
if (fragment == null) {
fragment = destination.createFragment(args)
transaction.add(containerId, fragment, tag)
} else {
transaction.attach(fragment)
}
transaction.setPrimaryNavigationFragment(fragment)
transaction.setReorderingAllowed(true)
transaction.commit()
dispatchOnNavigatorNavigated(destination.id, BACK_STACK_DESTINATION_ADDED)
}
}
사용자 지정 NavHostFragment를 만듭니다.
class CustomNavHostFragment: NavHostFragment() {
override fun onCreateNavController(navController: NavController) {
super.onCreateNavController(navController)
navController.navigatorProvider += PersistentNavigator(context!!, childFragmentManager, id)
}
}
조각 태그 대신 사용자 지정 태그를 사용하십시오.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation"
app:startDestination="@id/navigation_first">
<custom_fragment
android:id="@+id/navigation_first"
android:name="com.example.sample.FirstFragment"
android:label="FirstFragment" />
<custom_fragment
android:id="@+id/navigation_second"
android:name="com.example.sample.SecondFragment"
android:label="SecondFragment" />
</navigation>
NavHostFragment 대신 CustomNavHostFragment를 사용하십시오.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/nav_host_fragment"
android:name="com.example.sample.CustomNavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
샘플 프로젝트를 만들었습니다. 링크
사용자 지정 NavHostFragment를 만들지 않습니다. 나는 navController.navigatorProvider += navigator
.
fragments
다시 생성되지 않고 재 사용됨) 탐색에 문제가 있습니다. 각각의 menuitem
in bottomnavigationview
은 기본으로 간주됩니다. 따라서 BACK
를 누르면 앱이 종료되거나 최상위 구성 요소로 이동합니다. 더 나은 해결책은 YouTube 앱처럼 작동하는 것입니다. (1) 홈을 탭하십시오. (2) 트렌드 탭; (3)받은 편지함을 누릅니다. (4) 트렌드 탭; (5) 탭 BACK
-받은 편지함으로 이동합니다. (6) 탭 BACK
-홈으로 이동합니다. (7) 탭 BACK
-앱이 있습니다. 요약하면 BACK
' menuitems
' 사이의 YouTube 기능은 항목을 반복하지 않고 최신 기능 으로 돌아갑니다.
app:navGraph
활동의 NavHostFragment에서 제거 하는 것을 잊었을 것입니다 .
Google 샘플 링크 NavigationExtensions를 애플리케이션에 복사하고 예제별로 구성하면됩니다. 잘 작동합니다.
여러 시간의 연구 끝에 해결책을 찾았습니다. 그것은 항상 우리 앞에 있었다 :) popBackStack(destination, inclusive)
backStack에서 발견되면 주어진 목적지로 이동 하는 기능이 있습니다 . 부울을 반환하므로 컨트롤러가 조각을 찾지 못하면 수동으로 탐색 할 수 있습니다.
if(findNavController().popBackStack(R.id.settingsFragment, false)) {
Log.d(TAG, "SettingsFragment found in backStack")
} else {
Log.d(TAG, "SettingsFragment not found in backStack, navigate manually")
findNavController().navigate(R.id.settingsFragment)
}
인수 전달에 문제가있는 경우 다음을 추가하십시오.
fragment.arguments = args
클래스 KeepStateNavigator
지금은 사용할 수 없습니다.
해결 방법으로 가져온 모든 데이터를 뷰 모델에 저장하고 조각을 다시 만들 때 해당 데이터를 읽을 수 있도록 할 수 있습니다. 활동 컨텍스트를 사용하여보기를 가져와야합니다.
LiveData를 사용하여 데이터 수명주기를 인식 할 수 있도록 만들 수 있습니다.
@STAR_ZERO에서 제공하는 링크를 사용했는데 제대로 작동합니다. 뒤로 버튼에 문제가있는 분들은 이와 같이 활동 / 탐색 호스트에서 처리 할 수 있습니다.
override fun onBackPressed() {
if(navController.currentDestination!!.id!=R.id.homeFragment){
navController.navigate(R.id.homeFragment)
}else{
super.onBackPressed()
}
}
현재 대상이 루트 / 홈 프래그먼트 (일반적으로 하단 탐색보기의 첫 번째 프래그먼트)인지 확인하고, 그렇지 않은 경우 프래그먼트로 다시 이동하고, 예인 경우 앱을 종료하거나 원하는대로 수행합니다.
Btw,이 솔루션은 keep_state_fragment를 사용하여 STAR_ZERO에서 제공 한 위의 솔루션 링크와 함께 작동해야합니다 .
@ piotr-prus가 제공 한 솔루션이 도움이되었지만 현재 대상 확인을 추가해야했습니다.
if (navController.currentDestination?.id == resId) {
return //do not navigate
}
이 검사가 없으면 현재 대상은 백 스택에서 찾을 수 없기 때문에 실수로 탐색하면 다시 생성됩니다.
Android 문서 에 따르면 ,
FragmentContainerView를 사용하여 NavHostFragment를 만들거나 FragmentTransaction을 통해 NavHostFragment를 활동에 수동으로 추가하는 경우 Navigation.findNavController (Activity, @IdRes int)를 통해 활동의 onCreate ()에서 NavController를 검색하려는 시도가 실패합니다. 대신 NavHostFragment에서 직접 NavController를 검색해야합니다.
nav_host_fragment를-> FragmentContainerView 로 변경 하고 navController를 검색하십시오.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
이 접근 방식을 사용하여 탐색 구성 요소로 조각 상태를 유지할 수 있습니다.