androidx.compose.ui.node
Interfaces
CompositionLocalConsumerModifierNode |
Implementing this interface allows your |
Cmn
|
DelegatableNode |
Represents a |
Cmn
|
DelegatableNode.RegistrationHandle |
Cmn
|
|
DrawModifierNode |
A |
Cmn
|
GlobalPositionAwareModifierNode |
A |
Cmn
|
InteroperableComposeUiNode |
This interface allows the layout inspector to access inspect instances of Views that are associated with a Compose UI node. |
Cmn
|
LayoutAwareModifierNode |
A |
Cmn
|
LayoutModifierNode |
A |
Cmn
|
ObserverModifierNode |
|
Cmn
|
ParentDataModifierNode |
A |
Cmn
|
PointerInputModifierNode |
A |
Cmn
|
RootForTest |
The marker interface to be implemented by the root backing the composition. |
Cmn
|
RootForTest.UncaughtExceptionHandler |
An optional error handler that can be set to catch exceptions thrown during the layout, draw, and teardown phases of the associated composition. |
Cmn
|
SemanticsModifierNode |
A |
Cmn
|
TraversableNode |
Allows |
Cmn
|
UnplacedAwareModifierNode |
A |
Cmn
|
Classes
DelegatingNode |
A |
Cmn
|
DpTouchBoundsExpansion |
Describes the expansion of a |
Cmn
|
ModifierNodeElement |
A |
Cmn
|
Ref |
Value holder general purpose class. |
Cmn
|
TouchBoundsExpansion |
Describes the expansion of a |
Cmn
|
Objects
Annotations
InternalCoreApi |
Cmn
|
Enums
TraversableNode.Companion.TraverseDescendantsAction |
Tree traversal actions for the traverseDescendantsIf related functions: |
Cmn
|
Top-level functions summary
DpTouchBoundsExpansion |
DpTouchBoundsExpansion(start: Dp, top: Dp, end: Dp, bottom: Dp)Creates a |
Cmn
|
TouchBoundsExpansion |
TouchBoundsExpansion(start: Int, top: Int, end: Int, bottom: Int)Creates a |
Cmn
|
Extension functions summary
T |
<T : Any?> CompositionLocalConsumerModifierNode.currentValueOf(Returns the current value of |
Cmn
|
Unit |
If the node implements |
Cmn
|
Unit |
Call this function whenever a scroll chang happened in the LayoutNode that this |
Cmn
|
T? |
<T : TraversableNode> T.findNearestAncestor()Finds the nearest ancestor of the same class and key. |
Cmn
|
TraversableNode? |
Finds the nearest traversable ancestor with a matching |
Cmn
|
BeyondBoundsLayout? |
Call this function to find the nearest |
Cmn
|
Unit |
Invalidates this modifier's draw layer, ensuring that a draw pass will be run on the next frame. |
Cmn
|
Unit |
Invalidates draw for the entire subtree of this node. |
Cmn
|
Unit |
This will invalidate the current node's layer, and ensure that the layer is redrawn for the next frame. |
Cmn
|
Unit |
This invalidates the current node's measure result, and ensures that a re-measurement (the measurement block rerun) of this node will happen for the next frame. |
Cmn
|
Unit |
Invalidates measurements for the entire subtree of this node. |
Cmn
|
Unit |
This invalidates the current node's parent data, and ensures that layouts that utilize it will be scheduled to relayout for the next frame. |
Cmn
|
Unit |
This will invalidate the current node's placement result, and ensure that relayout (the placement block rerun) of this node will happen for the next frame . |
Cmn
|
Unit |
Invalidate semantics associated with this node. |
Cmn
|
Unit |
Invalidates the subtree of this layout, including layout, drawing, parent data, etc. |
Cmn
|
Unit |
<T : Modifier.Node & ObserverModifierNode> T.observeReads(block: () -> Unit)Use this function to observe snapshot reads for any target within the specified |
Cmn
|
Unit |
Performs the node remeasuring synchronously even if the node was not marked as needs remeasure before. |
Cmn
|
Unit |
Requests autofill for the LayoutNode that this |
Cmn
|
Density |
Returns the current |
Cmn
|
GraphicsContext |
Returns the current |
Cmn
|
LayoutCoordinates |
Returns the |
Cmn
|
LayoutDirection |
Returns the current |
Cmn
|
View |
The Android |
android
|
Unit |
<T : TraversableNode> T.traverseAncestors(block: (T) -> Boolean)Executes |
Cmn
|
Unit |
DelegatableNode.traverseAncestors( |
Cmn
|
Unit |
<T : TraversableNode> T.traverseChildren(block: (T) -> Boolean)Executes |
Cmn
|
Unit |
DelegatableNode.traverseChildren(Executes |
Cmn
|
Unit |
<T : TraversableNode> T.traverseDescendants(Conditionally executes |
Cmn
|
Unit |
DelegatableNode.traverseDescendants(Conditionally executes |
Cmn
|
Unit |
LayoutModifierNode.updateLayerBlock(layerBlock: (GraphicsLayerScope.() -> Unit)?)Updates the layer block of the |
Cmn
|
Top-level functions
DpTouchBoundsExpansion
fun DpTouchBoundsExpansion(
start: Dp = 0.dp,
top: Dp = 0.dp,
end: Dp = 0.dp,
bottom: Dp = 0.dp
): DpTouchBoundsExpansion
Creates a DpTouchBoundsExpansion that's aware of LayoutDirection. See DpTouchBoundsExpansion.start and DpTouchBoundsExpansion.end for more details about LayoutDirection.
The start, top, end and bottom represent the distance that the touch bounds is expanded along the corresponding edge.
TouchBoundsExpansion
fun TouchBoundsExpansion(start: Int = 0, top: Int = 0, end: Int = 0, bottom: Int = 0): TouchBoundsExpansion
Creates a TouchBoundsExpansion that's aware of LayoutDirection. See TouchBoundsExpansion.start and TouchBoundsExpansion.end for more details about LayoutDirection.
The start, top, end and bottom represent the amount of pixels that the touch bounds is expanded along the corresponding edge. Each value must be in the range of 0 to 32767 (inclusive).
Extension functions
currentValueOf
fun <T : Any?> CompositionLocalConsumerModifierNode.currentValueOf(
local: CompositionLocal<T>
): T
Returns the current value of local at the position in the composition hierarchy of this modifier's attached layout node.
Unlike CompositionLocal.current, reads via this function are not automatically tracked by Compose. Modifiers are not able to recompose in the same way that a Composable can, and therefore can't receive updates arbitrarily for a CompositionLocal.
Because CompositionLocals may change arbitrarily, it is strongly recommended to ensure that the composition local is observed instead of being read once. If you call currentValueOf inside of a modifier callback like LayoutModifierNode.measure or DrawModifierNode.draw, then Compose will track the CompositionLocal read. This happens automatically, because these Compose UI phases take place in a snapshot observer that tracks which states are read. If the value of the CompositionLocal changes, and it was read inside of the measure or draw phase, then that phase will automatically be invalidated.
For all other reads of a CompositionLocal, this function will not notify you when the value of the local changes. Modifier.Node classes that also implement ObserverModifierNode may observe CompositionLocals arbitrarily by performing the lookup in an observeReads block. To continue observing values of the CompositionLocal, it must be read again in an observeReads block during or after the ObserverModifierNode.onObservedReadsChanged callback is invoked. See below for an example of how to implement this observation pattern.
import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.Modifier import androidx.compose.ui.node.CompositionLocalConsumerModifierNode import androidx.compose.ui.node.ObserverModifierNode import androidx.compose.ui.node.currentValueOf import androidx.compose.ui.node.observeReads val LocalValue = compositionLocalOf { "abc123" } class ValueObserverModifierNode : Modifier.Node(), CompositionLocalConsumerModifierNode, ObserverModifierNode { private var observedValue: String? = null override fun onAttach() { onObservedReadsChanged() } override fun onDetach() { observedValue = null } override fun onObservedReadsChanged() { observeReads { observedValue = currentValueOf(LocalValue) // Do something with the new value } } }
This function will fail with an IllegalStateException if you attempt to read a CompositionLocal before the node is attached or after the node is detached.
| Parameters | |
|---|---|
local: CompositionLocal<T> |
The CompositionLocal to get the current value of |
| Returns | |
|---|---|
T |
The value provided by the nearest |
dispatchDraw
fun DelegatableNode.dispatchDraw(scope: ContentDrawScope): Unit
If the node implements DrawModifierNode, then this will just call DrawModifierNode.draw. if it does NOT implement DrawModifierNode, it will dispatch draw recursively to any of its direct delegates which DO implement DrawModifierNode
This can be useful when there is a DelegatingNode which wants to ensure all draw calls are executed of any delegates, but the implementation of the node may not have knowledge of which delegates actually implement DrawModifierNode.
dispatchOnScrollChanged
fun DelegatableNode.dispatchOnScrollChanged(delta: Offset): Unit
Call this function whenever a scroll chang happened in the LayoutNode that this DelegatableNode is attached to to let the underlying platform know that a scroll event happened in this LayoutNode.
On Android this will trigger a ViewTreeObserver onScrollChanged callback.
| Parameters | |
|---|---|
delta: Offset |
The scroll delta that was consumed by this node. |
findNearestAncestor
fun <T : TraversableNode> T.findNearestAncestor(): T?
Finds the nearest ancestor of the same class and key.
findNearestAncestor
fun DelegatableNode.findNearestAncestor(key: Any?): TraversableNode?
Finds the nearest traversable ancestor with a matching key.
findNearestBeyondBoundsLayoutAncestor
fun DelegatableNode.findNearestBeyondBoundsLayoutAncestor(): BeyondBoundsLayout?
Call this function to find the nearest BeyondBoundsLayout to the current node.
invalidateDraw
fun DrawModifierNode.invalidateDraw(): Unit
Invalidates this modifier's draw layer, ensuring that a draw pass will be run on the next frame.
invalidateDrawForSubtree
fun DelegatableNode.invalidateDrawForSubtree(): Unit
Invalidates draw for the entire subtree of this node.
Note that invalidateDraw is preferable in most cases, however it is only guaranteed to invalidate draw for that specific node, and it is possible that draw nodes that are underneath it could be cached and thus their draw methods will not get re-executed. Use this API if you need to ensure that draw is called for all draw nodes below this one. This might be necessary in certain situations where you are updating some data which you know descendant nodes use, but you are not relaying on automatic snapshot observation through androidx.compose.runtime.MutableState.
Calling this method can be a relatively expensive operation as it will cause the entire subtree to redraw instead of just parts that are otherwise invalidated. invalidateDraw is preferable in most cases, and this should only be used when absolutely necessary.
invalidateLayer
fun LayoutModifierNode.invalidateLayer(): Unit
This will invalidate the current node's layer, and ensure that the layer is redrawn for the next frame.
invalidateMeasurement
fun LayoutModifierNode.invalidateMeasurement(): Unit
This invalidates the current node's measure result, and ensures that a re-measurement (the measurement block rerun) of this node will happen for the next frame.
invalidateMeasurementForSubtree
fun DelegatableNode.invalidateMeasurementForSubtree(): Unit
Invalidates measurements for the entire subtree of this node.
Note that invalidateMeasurement is preferable in most cases, however it is only guaranteed to invalidate measurement for that specific node, and it is possible that layout nodes that are underneath it could be cached and thus their measure policies will not get re-executed. Use this API if you need to ensure that measure is called for all layout nodes below this one. This might be necessary in certain situations where you are updating some data which you know descendant nodes use, but you are not relaying on automatic snapshot observation through androidx.compose.runtime.MutableState.
Calling this method can be a relatively expensive operation as it will cause the entire subtree to relayout instead of just parts that are otherwise invalidated. invalidateMeasurement is preferable in most cases, and this should only be used when absolutely necessary.
invalidateParentData
fun ParentDataModifierNode.invalidateParentData(): Unit
This invalidates the current node's parent data, and ensures that layouts that utilize it will be scheduled to relayout for the next frame.
invalidatePlacement
fun LayoutModifierNode.invalidatePlacement(): Unit
This will invalidate the current node's placement result, and ensure that relayout (the placement block rerun) of this node will happen for the next frame .
invalidateSemantics
fun SemanticsModifierNode.invalidateSemantics(): Unit
Invalidate semantics associated with this node. This will reset the SemanticsConfiguration associated with the layout node backing this modifier node, and will re-calculate it the next time the SemanticsConfiguration is read.
Semantics are automatically invalidated when backed by mutable state, or if the hierarchy is recomposed. In these cases SemanticsModifierNode.applySemantics is called and the latest semantics values are applied. However in cases where semantics properties are not backed by mutable state objects, a change to the semantic property will not trigger SemanticsModifierNode.applySemantics. This function can be used to manually invalidate semantics to ensure that SemanticsModifierNode.applySemantics will be called the next time the SemanticsConfiguration is read.
invalidateSubtree
fun DelegatableNode.invalidateSubtree(): Unit
Invalidates the subtree of this layout, including layout, drawing, parent data, etc.
Calling this method can be a relatively expensive operation as it will cause the entire subtree to relayout and redraw instead of just parts that are otherwise invalidated. Its use should be limited to structural changes. This might be necessary in certain situations where you are updating some data which you know descendant nodes use, but you are not relaying on automatic snapshot observation through androidx.compose.runtime.MutableState.
observeReads
fun <T : Modifier.Node & ObserverModifierNode> T.observeReads(block: () -> Unit): Unit
Use this function to observe snapshot reads for any target within the specified block. ObserverModifierNode.onObservedReadsChanged is called when any of the observed values within the snapshot change.
remeasureSync
fun LayoutModifierNode.remeasureSync(): Unit
Performs the node remeasuring synchronously even if the node was not marked as needs remeasure before. Useful for cases like when during scrolling you need to re-execute the measure block to consume the scroll offset and remeasure your children in a blocking way.
requestAutofill
fun DelegatableNode.requestAutofill(): Unit
Requests autofill for the LayoutNode that this DelegatableNode is attached to. If the node does not have any autofill semantic properties set, then the request still may be sent to the Autofill service, but no response is expected.
requireDensity
fun DelegatableNode.requireDensity(): Density
Returns the current Density of the LayoutNode that this DelegatableNode is attached to. If the node is not attached, this function will throw an IllegalStateException.
requireGraphicsContext
fun DelegatableNode.requireGraphicsContext(): GraphicsContext
Returns the current GraphicsContext of the Owner
requireLayoutCoordinates
fun DelegatableNode.requireLayoutCoordinates(): LayoutCoordinates
Returns the LayoutCoordinates of this node.
To get a signal when the LayoutCoordinates become available, or when its parent places it, implement LayoutAwareModifierNode.
| Throws | |
|---|---|
kotlin.IllegalStateException |
When either this node is not attached, or the |
requireLayoutDirection
fun DelegatableNode.requireLayoutDirection(): LayoutDirection
Returns the current LayoutDirection of the LayoutNode that this DelegatableNode is attached to. If the node is not attached, this function will throw an IllegalStateException.
requireView
fun DelegatableNode.requireView(): View
The Android View hosting the composition.
| Throws | |
|---|---|
kotlin.IllegalStateException |
If the modifier node is not |
traverseAncestors
fun <T : TraversableNode> T.traverseAncestors(block: (T) -> Boolean): Unit
Executes block for all ancestors of the same class and key.
Note: The parameter block's return boolean value will determine if the traversal will continue (true = continue, false = cancel).
import androidx.compose.ui.Modifier import androidx.compose.ui.node.traverseAncestors val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseAncestors { // Because I use the existing key of the class, I can guarantee 'it' will be of the same // type as the class, so I can call my functions directly. it.doSomethingWithAncestor() // Return true to continue searching the tree after a match. If you were looking to // match only some of the nodes, you could return false and stop executing the search. true } }
traverseAncestors
fun DelegatableNode.traverseAncestors(
key: Any?,
block: (TraversableNode) -> Boolean
): Unit
Executes block for all ancestors with a matching key.
Note: The parameter block's return boolean value will determine if the traversal will continue (true = continue, false = cancel).
import androidx.compose.ui.Modifier import androidx.compose.ui.node.traverseAncestors val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseAncestors(traverseKey) { if (it is CustomTraversableModifierNode) { it.doSomethingWithAncestor() } // Return true to continue searching the tree after a match. If you were looking to // match only some of the nodes, you could return false and stop executing the search. true } }
traverseChildren
fun <T : TraversableNode> T.traverseChildren(block: (T) -> Boolean): Unit
Executes block for all direct children of the node that are of the same class.
Note 1: This stops at the children and does not include grandchildren and so on down the tree.
Note 2: The parameter block's return boolean value will determine if the traversal will continue (true = continue, false = cancel).
import androidx.compose.ui.Modifier import androidx.compose.ui.node.traverseChildren val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseChildren { // Because I use the existing key of the class, I can guarantee 'it' will be of the same // type as the class, so I can call my functions directly. it.doSomethingWithChild() // Return true to continue searching the tree after a match. If you were looking to // match only some of the nodes, you could return false and stop executing the search. true } }
traverseChildren
fun DelegatableNode.traverseChildren(
key: Any?,
block: (TraversableNode) -> Boolean
): Unit
Executes block for all direct children of the node with a matching key.
Note 1: This stops at the children and does not include grandchildren and so on down the tree.
Note 2: The parameter block's return boolean value will determine if the traversal will continue (true = continue, false = cancel).
import androidx.compose.ui.Modifier import androidx.compose.ui.node.traverseChildren val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseChildren(traverseKey) { if (it is CustomTraversableModifierNode) { it.doSomethingWithChild() } // Return true to continue searching the tree after a match. If you were looking to // match only some of the nodes, you could return false and stop executing the search. true } }
traverseDescendants
fun <T : TraversableNode> T.traverseDescendants(
block: (T) -> TraversableNode.Companion.TraverseDescendantsAction
): Unit
Conditionally executes block for each descendant of the same class.
Note 1: For nodes that do not have the same key, it will continue to execute the block for the descendants below that non-matching node (where there may be a node that matches).
Note 2: The parameter block's return value TraverseDescendantsAction will determine the next step in the traversal.
import androidx.compose.ui.Modifier import androidx.compose.ui.node.TraversableNode.Companion.TraverseDescendantsAction import androidx.compose.ui.node.traverseDescendants val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseDescendants { // Because I use the existing key of the class, I can guarantee 'it' will be of the same // type as the class, so I can call my functions directly. it.doSomethingWithDescendant() // [traverseDescendants()] actually has three options: // - ContinueTraversal // - SkipSubtreeAndContinueTraversal - rarely used // - CancelTraversal // They are pretty self explanatory. Usually, you just want to continue or cancel the // search. In some rare cases, you might want to skip the subtree but continue searching // the tree. TraverseDescendantsAction.ContinueTraversal } }
traverseDescendants
fun DelegatableNode.traverseDescendants(
key: Any?,
block: (TraversableNode) -> TraversableNode.Companion.TraverseDescendantsAction
): Unit
Conditionally executes block for each descendant with a matching key.
Note 1: For nodes that do not have the same key, it will continue to execute the block for descendants below that non-matching node (where there may be a node that matches).
Note 2: The parameter block's return value TraverseDescendantsAction will determine the next step in the traversal.
import androidx.compose.ui.Modifier import androidx.compose.ui.node.TraversableNode.Companion.TraverseDescendantsAction import androidx.compose.ui.node.traverseDescendants val customTraversableModifierNode = CustomTraversableModifierNode() with(customTraversableModifierNode) { traverseDescendants(traverseKey) { if (it is CustomTraversableModifierNode) { it.doSomethingWithDescendant() } // [traverseDescendants()] actually has three options: // - ContinueTraversal // - SkipSubtreeAndContinueTraversal - rarely used // - CancelTraversal // They are pretty self explanatory. Usually, you just want to continue or cancel the // search. In some rare cases, you might want to skip the subtree but continue searching // the tree. TraverseDescendantsAction.ContinueTraversal } }
updateLayerBlock
fun LayoutModifierNode.updateLayerBlock(layerBlock: (GraphicsLayerScope.() -> Unit)?): Unit
Updates the layer block of the LayoutModifierNode. This will mark the layer as invalidated and schedule a refresh of the layer.
Updating the layer lambda using this method is cheaper than invalidating placement and placing the layout with a new layer block. This API is expected to be used alongside Placeable.placeAt with a layerBlock parameter passed. This will override/update the layerBlock passed in that API. Whichever one was called last should "win".
| Parameters | |
|---|---|
layerBlock: (GraphicsLayerScope.() -> Unit)? |
the snapshot-observed lambda used to set properties on the layer. if |
| See also | |
|---|---|
placeAt |