1 /*
2  * Copyright 2021 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 androidx.compose.ui.layout
18 
19 import androidx.compose.runtime.Stable
20 import androidx.compose.ui.Modifier
21 import androidx.compose.ui.internal.JvmDefaultWithCompatibility
22 import androidx.compose.ui.node.LayoutAwareModifierNode
23 import androidx.compose.ui.node.ModifierNodeElement
24 import androidx.compose.ui.platform.InspectorInfo
25 
26 /**
27  * Invoke [onPlaced] after the parent [LayoutModifier] and parent layout has been placed and before
28  * child [LayoutModifier] is placed. This allows child [LayoutModifier] to adjust its own placement
29  * based on where the parent is.
30  *
31  * @sample androidx.compose.ui.samples.OnPlaced
32  */
33 @Stable
Modifiernull34 fun Modifier.onPlaced(onPlaced: (LayoutCoordinates) -> Unit) = this then OnPlacedElement(onPlaced)
35 
36 private class OnPlacedElement(val onPlaced: (LayoutCoordinates) -> Unit) :
37     ModifierNodeElement<OnPlacedNode>() {
38     override fun create() = OnPlacedNode(callback = onPlaced)
39 
40     override fun update(node: OnPlacedNode) {
41         node.callback = onPlaced
42     }
43 
44     override fun InspectorInfo.inspectableProperties() {
45         name = "onPlaced"
46         properties["onPlaced"] = onPlaced
47     }
48 
49     override fun equals(other: Any?): Boolean {
50         if (this === other) return true
51         if (other !is OnPlacedElement) return false
52 
53         if (onPlaced !== other.onPlaced) return false
54 
55         return true
56     }
57 
58     override fun hashCode(): Int {
59         return onPlaced.hashCode()
60     }
61 }
62 
63 private class OnPlacedNode(var callback: (LayoutCoordinates) -> Unit) :
64     LayoutAwareModifierNode, Modifier.Node() {
65 
onPlacednull66     override fun onPlaced(coordinates: LayoutCoordinates) {
67         callback(coordinates)
68     }
69 }
70 
71 /**
72  * A modifier whose [onPlaced] is called after the parent [LayoutModifier] and parent layout has
73  * been placed and before child [LayoutModifier] is placed. This allows child [LayoutModifier] to
74  * adjust its own placement based on where the parent is.
75  *
76  * @sample androidx.compose.ui.samples.OnPlaced
77  */
78 @JvmDefaultWithCompatibility
79 interface OnPlacedModifier : Modifier.Element {
80     /**
81      * [onPlaced] is called after parent [LayoutModifier] and parent layout gets placed and before
82      * any child [LayoutModifier] is placed.
83      *
84      * [coordinates] provides [LayoutCoordinates] of the [OnPlacedModifier]. Placement in both
85      * parent [LayoutModifier] and parent layout can be calculated using the [LayoutCoordinates].
86      */
onPlacednull87     fun onPlaced(coordinates: LayoutCoordinates)
88 }
89