1 /*
2 * Copyright 2024 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 @file:JvmName("ViewTree")
18
19 package androidx.core.viewtree
20
21 import android.view.View
22 import android.view.ViewParent
23
24 /**
25 * Assigns the disjoint parent of the given `view` to `parent`.
26 *
27 * A disjoint parent acts as an alternative to [View.getParent] and is used to link two disjoint
28 * view hierarchies together. ViewOverlays, popups, and dialogs are all examples of when two view
29 * hierarchies are disjoint but related. In all of these cases, there is either a new window or new
30 * root view that has no parent of its own but conceptually is owned or otherwise related to another
31 * specific view in the disjoint hierarchy.
32 *
33 * A disjoint parent is only used when a view has no parent of its own, so it is important to set
34 * this tag only once at the root of the tree that is disconnected from its parent. AndroidX
35 * automatically sets disjoint parents for hierarchies it creates in certain use cases, like for
36 * view overlays (used in transitions).
37 *
38 * Setting the disjoint parent allows other components to resolve information from the disjoint
39 * parent. AndroidX will use disjoint parents to resolve values stored in the view tree, like
40 * ViewModel store owners, lifecycle owners, and more. They are not used or set by the platform.
41 * Other View-based libraries should consider setting this property to allow these and similar
42 * lookups to occur between disconnected view hierarchies. Opting in is not mandatory, and therefore
43 * disjoint parents are not guaranteed to be a comprehensive source of view ownership in all
44 * situations.
45 *
46 * To prevent a leak, a view must not outlive its disjoint parent. Additionally, you should avoid
47 * accidentally creating a cycle in the parent and disjoint parent hierarchy. A view can be
48 * re-parented to a different disjoint parent by calling this method again in the future, and can
49 * have its disjoint parent cleared by setting it to `null`.
50 *
51 * @param parent The disjoint parent to set on `view`
52 * @receiver The view to set the disjoint parent of
53 * @see [getParentOrViewTreeDisjointParent]
54 */
setViewTreeDisjointParentnull55 public fun View.setViewTreeDisjointParent(parent: ViewParent?) {
56 setTag(R.id.view_tree_disjoint_parent, parent)
57 }
58
59 /**
60 * Looks up a disjoint parent previously set by [setViewTreeDisjointParent].
61 *
62 * @return The [View.getParent] or the disjoint parent of the given `view`. If present, the parent
63 * view is always preferred by this method over the disjoint parent. If the view has neither a
64 * parent nor a disjoint parent, `null` is returned.
65 * @receiver The view to get the parent or disjoint parent from
66 */
getParentOrViewTreeDisjointParentnull67 public fun View.getParentOrViewTreeDisjointParent(): ViewParent? {
68 val parent = parent
69 if (parent != null) return parent
70
71 val djParent = getTag(R.id.view_tree_disjoint_parent)
72 return if ((djParent is ViewParent)) djParent else null
73 }
74