1 /* <lambda>null2 * Copyright (C) 2017 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 package androidx.navigation 17 18 import android.app.Activity 19 import android.view.View 20 import androidx.annotation.IdRes 21 import androidx.core.app.ActivityCompat 22 import androidx.savedstate.SavedState 23 import java.lang.ref.WeakReference 24 25 public actual object Navigation { 26 /** 27 * Find a [NavController] given the id of a View and its containing [Activity]. This is a 28 * convenience wrapper around [findNavController]. 29 * 30 * This method will locate the [NavController] associated with this view. This is automatically 31 * populated for the id of a [NavHost] and its children. 32 * 33 * @param activity The Activity hosting the view 34 * @param viewId The id of the view to search from 35 * @return the [NavController] associated with the view referenced by id 36 * @throws IllegalStateException if the given viewId does not correspond with a [NavHost] or is 37 * not within a NavHost. 38 */ 39 @JvmStatic 40 public fun findNavController(activity: Activity, @IdRes viewId: Int): NavController { 41 val view = ActivityCompat.requireViewById<View>(activity, viewId) 42 return findViewNavController(view) 43 ?: throw IllegalStateException( 44 "Activity $activity does not have a NavController set on $viewId" 45 ) 46 } 47 48 /** 49 * Find a [NavController] given a local [View]. 50 * 51 * This method will locate the [NavController] associated with this view. This is automatically 52 * populated for views that are managed by a [NavHost] and is intended for use by various 53 * [listener][android.view.View.OnClickListener] interfaces. 54 * 55 * @param view the view to search from 56 * @return the locally scoped [NavController] to the given view 57 * @throws IllegalStateException if the given view does not correspond with a [NavHost] or is 58 * not within a NavHost. 59 */ 60 @JvmStatic 61 public fun findNavController(view: View): NavController { 62 return findViewNavController(view) 63 ?: throw IllegalStateException("View $view does not have a NavController set") 64 } 65 66 /** 67 * Create an [android.view.View.OnClickListener] for navigating to a destination. This supports 68 * both navigating via an [action][NavDestination.getAction] and directly navigating to a 69 * destination. 70 * 71 * @param resId an [action][NavDestination.getAction] id or a destination id to navigate to when 72 * the view is clicked 73 * @param args arguments to pass to the final destination 74 * @return a new click listener for setting on an arbitrary view 75 */ 76 @JvmStatic 77 @JvmOverloads 78 public fun createNavigateOnClickListener( 79 @IdRes resId: Int, 80 args: SavedState? = null 81 ): View.OnClickListener { 82 return View.OnClickListener { view -> findNavController(view).navigate(resId, args) } 83 } 84 85 /** 86 * Create an [android.view.View.OnClickListener] for navigating to a destination via a generated 87 * [NavDirections]. 88 * 89 * @param directions directions that describe this navigation operation 90 * @return a new click listener for setting on an arbitrary view 91 */ 92 @JvmStatic 93 public fun createNavigateOnClickListener(directions: NavDirections): View.OnClickListener { 94 return View.OnClickListener { view -> findNavController(view).navigate(directions) } 95 } 96 97 /** 98 * Associates a NavController with the given View, allowing developers to use 99 * [findNavController] and [findNavController] with that View or any of its children to retrieve 100 * the NavController. 101 * 102 * This is generally called for you by the hosting [NavHost]. 103 * 104 * @param view View that should be associated with the given NavController 105 * @param controller The controller you wish to later retrieve via [findNavController] 106 */ 107 @JvmStatic 108 public fun setViewNavController(view: View, controller: NavController?) { 109 view.setTag(R.id.nav_controller_view_tag, controller) 110 } 111 112 /** 113 * Recurse up the view hierarchy, looking for the NavController 114 * 115 * @param view the view to search from 116 * @return the locally scoped [NavController] to the given view, if found 117 */ 118 private fun findViewNavController(view: View): NavController? = 119 generateSequence(view) { it.parent as? View? } 120 .mapNotNull { getViewNavController(it) } 121 .firstOrNull() 122 123 @Suppress("UNCHECKED_CAST") 124 private fun getViewNavController(view: View): NavController? { 125 val tag = view.getTag(R.id.nav_controller_view_tag) 126 var controller: NavController? = null 127 if (tag is WeakReference<*>) { 128 controller = (tag as WeakReference<NavController>).get() 129 } else if (tag is NavController) { 130 controller = tag 131 } 132 return controller 133 } 134 } 135