|
| 1 | +///* |
| 2 | +// * Copyright 2019, The Android Open Source Project |
| 3 | +// * |
| 4 | +// * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +// * you may not use this file except in compliance with the License. |
| 6 | +// * You may obtain a copy of the License at |
| 7 | +// * |
| 8 | +// * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +// * |
| 10 | +// * Unless required by applicable law or agreed to in writing, software |
| 11 | +// * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +// * See the License for the specific language governing permissions and |
| 14 | +// * limitations under the License. |
| 15 | +// */ |
| 16 | +// |
| 17 | +//package com.smarttoolfactory.tutorial8_2dynamicfeatures_complexarchitecture |
| 18 | +// |
| 19 | +//import android.content.Intent |
| 20 | +//import android.util.SparseArray |
| 21 | +//import androidx.core.util.forEach |
| 22 | +//import androidx.core.util.set |
| 23 | +//import androidx.fragment.app.FragmentManager |
| 24 | +//import androidx.lifecycle.LiveData |
| 25 | +//import androidx.lifecycle.MutableLiveData |
| 26 | +//import androidx.navigation.NavController |
| 27 | +//import androidx.navigation.fragment.NavHostFragment |
| 28 | +//import com.google.android.material.bottomnavigation.BottomNavigationView |
| 29 | +// |
| 30 | +///** |
| 31 | +// * Manages the various graphs needed for a [BottomNavigationView]. |
| 32 | +// * |
| 33 | +// * This sample is a workaround until the Navigation Component supports multiple back stacks. |
| 34 | +// */ |
| 35 | +//fun BottomNavigationView.setupWithDynamicNavController( |
| 36 | +// navGraphPair: List<Pair<Int, Int>>, |
| 37 | +// fragmentManager: FragmentManager, |
| 38 | +// containerId: Int, |
| 39 | +// intent: Intent |
| 40 | +//): LiveData<NavController> { |
| 41 | +// |
| 42 | +// // Map of tags |
| 43 | +// val graphIdToTagMap = SparseArray<String>() |
| 44 | +// // Result. Mutable live data with the selected controlled |
| 45 | +// val selectedNavController = MutableLiveData<NavController>() |
| 46 | +// |
| 47 | +// var firstFragmentGraphId = 0 |
| 48 | +// |
| 49 | +// // First create a NavHostFragment for each NavGraph ID |
| 50 | +// navGraphPair.forEachIndexed { index, navGraphPair -> |
| 51 | +// val fragmentTag = getFragmentTag(index) |
| 52 | +// |
| 53 | +// // Find or create the Navigation host fragment |
| 54 | +// val navHostFragment = obtainNavHostFragment( |
| 55 | +// fragmentManager, |
| 56 | +// fragmentTag, |
| 57 | +// navGraphPair, |
| 58 | +// containerId |
| 59 | +// ) |
| 60 | +// |
| 61 | +// // Obtain its id |
| 62 | +// val graphId = navHostFragment.navController.graph.id |
| 63 | +// |
| 64 | +// if (index == 0) { |
| 65 | +// firstFragmentGraphId = graphId |
| 66 | +// } |
| 67 | +// |
| 68 | +// // Save to the map |
| 69 | +// graphIdToTagMap[graphId] = fragmentTag |
| 70 | +// |
| 71 | +// // Attach or detach nav host fragment depending on whether it's the selected item. |
| 72 | +// if (this.selectedItemId == graphId) { |
| 73 | +// // Update livedata with the selected graph |
| 74 | +// selectedNavController.value = navHostFragment.navController |
| 75 | +// attachNavHostFragment(fragmentManager, navHostFragment, index == 0) |
| 76 | +// } else { |
| 77 | +// detachNavHostFragment(fragmentManager, navHostFragment) |
| 78 | +// } |
| 79 | +// } |
| 80 | +// |
| 81 | +// // Now connect selecting an item with swapping Fragments |
| 82 | +// var selectedItemTag = graphIdToTagMap[this.selectedItemId] |
| 83 | +// val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId] |
| 84 | +// var isOnFirstFragment = selectedItemTag == firstFragmentTag |
| 85 | +// |
| 86 | +// // When a navigation item is selected |
| 87 | +// setOnNavigationItemSelectedListener { item -> |
| 88 | +// // Don't do anything if the state is state has already been saved. |
| 89 | +// if (fragmentManager.isStateSaved) { |
| 90 | +// false |
| 91 | +// } else { |
| 92 | +// val newlySelectedItemTag = graphIdToTagMap[item.itemId] |
| 93 | +// if (selectedItemTag != newlySelectedItemTag) { |
| 94 | +// // Pop everything above the first fragment (the "fixed start destination") |
| 95 | +// fragmentManager.popBackStack( |
| 96 | +// firstFragmentTag, |
| 97 | +// FragmentManager.POP_BACK_STACK_INCLUSIVE |
| 98 | +// ) |
| 99 | +// val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) |
| 100 | +// as NavHostFragment |
| 101 | +// |
| 102 | +// // Exclude the first fragment tag because it's always in the back stack. |
| 103 | +// if (firstFragmentTag != newlySelectedItemTag) { |
| 104 | +// // Commit a transaction that cleans the back stack and adds the first fragment |
| 105 | +// // to it, creating the fixed started destination. |
| 106 | +// fragmentManager.beginTransaction() |
| 107 | +// .attach(selectedFragment) |
| 108 | +// .setPrimaryNavigationFragment(selectedFragment) |
| 109 | +// .apply { |
| 110 | +// // Detach all other Fragments |
| 111 | +// graphIdToTagMap.forEach { _, fragmentTagIter -> |
| 112 | +// if (fragmentTagIter != newlySelectedItemTag) { |
| 113 | +// detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!) |
| 114 | +// } |
| 115 | +// } |
| 116 | +// } |
| 117 | +// .addToBackStack(firstFragmentTag) |
| 118 | +// .setCustomAnimations( |
| 119 | +// R.anim.nav_default_enter_anim, |
| 120 | +// R.anim.nav_default_exit_anim, |
| 121 | +// R.anim.nav_default_pop_enter_anim, |
| 122 | +// R.anim.nav_default_pop_exit_anim |
| 123 | +// ) |
| 124 | +// .setReorderingAllowed(true) |
| 125 | +// .commit() |
| 126 | +// } |
| 127 | +// selectedItemTag = newlySelectedItemTag |
| 128 | +// isOnFirstFragment = selectedItemTag == firstFragmentTag |
| 129 | +// selectedNavController.value = selectedFragment.navController |
| 130 | +// true |
| 131 | +// } else { |
| 132 | +// false |
| 133 | +// } |
| 134 | +// } |
| 135 | +// } |
| 136 | +// |
| 137 | +// // Optional: on item reselected, pop back stack to the destination of the graph |
| 138 | +// setupItemReselected(graphIdToTagMap, fragmentManager) |
| 139 | +// |
| 140 | +// // Handle deep link |
| 141 | +// setupDeepLinks(navGraphIds, fragmentManager, containerId, intent) |
| 142 | +// |
| 143 | +// // Finally, ensure that we update our BottomNavigationView when the back stack changes |
| 144 | +// fragmentManager.addOnBackStackChangedListener { |
| 145 | +// if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) { |
| 146 | +// this.selectedItemId = firstFragmentGraphId |
| 147 | +// } |
| 148 | +// |
| 149 | +// // Reset the graph if the currentDestination is not valid (happens when the back |
| 150 | +// // stack is popped after using the back button). |
| 151 | +// selectedNavController.value?.let { controller -> |
| 152 | +// if (controller.currentDestination == null) { |
| 153 | +// controller.navigate(controller.graph.id) |
| 154 | +// } |
| 155 | +// } |
| 156 | +// } |
| 157 | +// return selectedNavController |
| 158 | +//} |
| 159 | +// |
| 160 | +//private fun BottomNavigationView.setupDeepLinks( |
| 161 | +// navGraphIds: List<Int>, |
| 162 | +// fragmentManager: FragmentManager, |
| 163 | +// containerId: Int, |
| 164 | +// intent: Intent |
| 165 | +//) { |
| 166 | +// navGraphIds.forEachIndexed { index, navGraphId -> |
| 167 | +// val fragmentTag = getFragmentTag(index) |
| 168 | +// |
| 169 | +// // Find or create the Navigation host fragment |
| 170 | +// val navHostFragment = obtainNavHostFragment( |
| 171 | +// fragmentManager, |
| 172 | +// fragmentTag, |
| 173 | +// navGraphId, |
| 174 | +// containerId |
| 175 | +// ) |
| 176 | +// // Handle Intent |
| 177 | +// if (navHostFragment.navController.handleDeepLink(intent) |
| 178 | +// && selectedItemId != navHostFragment.navController.graph.id |
| 179 | +// ) { |
| 180 | +// this.selectedItemId = navHostFragment.navController.graph.id |
| 181 | +// } |
| 182 | +// } |
| 183 | +//} |
| 184 | +// |
| 185 | +//private fun BottomNavigationView.setupItemReselected( |
| 186 | +// graphIdToTagMap: SparseArray<String>, |
| 187 | +// fragmentManager: FragmentManager |
| 188 | +//) { |
| 189 | +// setOnNavigationItemReselectedListener { item -> |
| 190 | +// val newlySelectedItemTag = graphIdToTagMap[item.itemId] |
| 191 | +// val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) |
| 192 | +// as NavHostFragment |
| 193 | +// val navController = selectedFragment.navController |
| 194 | +// // Pop the back stack to the start destination of the current navController graph |
| 195 | +// navController.popBackStack( |
| 196 | +// navController.graph.startDestination, false |
| 197 | +// ) |
| 198 | +// } |
| 199 | +//} |
| 200 | +// |
| 201 | +//private fun detachNavHostFragment( |
| 202 | +// fragmentManager: FragmentManager, |
| 203 | +// navHostFragment: NavHostFragment |
| 204 | +//) { |
| 205 | +// fragmentManager.beginTransaction() |
| 206 | +// .detach(navHostFragment) |
| 207 | +// .commitNow() |
| 208 | +//} |
| 209 | +// |
| 210 | +//private fun attachNavHostFragment( |
| 211 | +// fragmentManager: FragmentManager, |
| 212 | +// navHostFragment: NavHostFragment, |
| 213 | +// isPrimaryNavFragment: Boolean |
| 214 | +//) { |
| 215 | +// fragmentManager.beginTransaction() |
| 216 | +// .attach(navHostFragment) |
| 217 | +// .apply { |
| 218 | +// if (isPrimaryNavFragment) { |
| 219 | +// setPrimaryNavigationFragment(navHostFragment) |
| 220 | +// } |
| 221 | +// } |
| 222 | +// .commitNow() |
| 223 | +// |
| 224 | +//} |
| 225 | +// |
| 226 | +//private fun obtainNavHostFragment( |
| 227 | +// fragmentManager: FragmentManager, |
| 228 | +// fragmentTag: String, |
| 229 | +// navGraphPair: Pair<Int, Int>, |
| 230 | +// containerId: Int |
| 231 | +//): NavHostFragment { |
| 232 | +// // If the Nav Host fragment exists, return it |
| 233 | +// val existingFragment = fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment? |
| 234 | +// existingFragment?.let { return it } |
| 235 | +// |
| 236 | +// // Otherwise, create it and return it. |
| 237 | +// val navHostFragment = NavHostFragment.create(navGraphId) |
| 238 | +// fragmentManager.beginTransaction() |
| 239 | +// .add(containerId, navHostFragment, fragmentTag) |
| 240 | +// .commitNow() |
| 241 | +// return navHostFragment |
| 242 | +//} |
| 243 | +// |
| 244 | +//private fun FragmentManager.isOnBackStack(backStackName: String): Boolean { |
| 245 | +// val backStackCount = backStackEntryCount |
| 246 | +// for (index in 0 until backStackCount) { |
| 247 | +// if (getBackStackEntryAt(index).name == backStackName) { |
| 248 | +// return true |
| 249 | +// } |
| 250 | +// } |
| 251 | +// return false |
| 252 | +//} |
| 253 | +// |
| 254 | +//private fun getFragmentTag(index: Int) = "bottomNavigation#$index" |
0 commit comments