Modifier.Node

Known direct subclasses
DelegatingNode

A Modifier.Node which is able to delegate work to other Modifier.Node instances.


The longer-lived object that is created for each Modifier.Element applied to a androidx.compose.ui.layout.Layout. Most Modifier.Node implementations will have a corresponding "Modifier Factory" extension method on Modifier that will allow them to be used indirectly, without ever implementing a Modifier.Node subclass directly. In some cases it may be useful to define a custom Modifier.Node subclass in order to efficiently implement some collection of behaviors that requires maintaining state over time and over many recompositions where the various provided Modifier factories are not sufficient.

When a Modifier is set on a androidx.compose.ui.layout.Layout, each Modifier.Element contained in that linked list will result in a corresponding Modifier.Node instance in a matching linked list of Modifier.Nodes that the androidx.compose.ui.layout.Layout will hold on to. As subsequent Modifier chains get set on the androidx.compose.ui.layout.Layout, the linked list of Modifier.Nodes will be diffed and updated as appropriate, even though the Modifier instance might be completely new. As a result, the lifetime of a Modifier.Node is the intersection of the lifetime of the androidx.compose.ui.layout.Layout that it lives on and a corresponding Modifier.Element being present in the androidx.compose.ui.layout.Layout's Modifier.

If one creates a subclass of Modifier.Node, it is expected that it will implement one or more interfaces that interact with the various Compose UI subsystems. To use the Modifier.Node subclass, it is expected that it will be instantiated by adding a androidx.compose.ui.node.ModifierNodeElement to a Modifier chain.

Summary

Public constructors

Cmn

Public functions

open Unit

Called when the node is attached to a androidx.compose.ui.layout.Layout which is part of the UI tree.

Cmn
open Unit

Called when the node is not attached to a androidx.compose.ui.layout.Layout which is not a part of the UI tree anymore.

Cmn
open Unit

Called when the node is about to be moved to a pool of layouts ready to be reused.

Cmn
Unit
sideEffect(effect: () -> Unit)

This can be called to register effect as a function to be executed after all of the changes to the tree are applied.

Cmn

Public properties

CoroutineScope

A CoroutineScope that can be used to launch tasks that should run while the node is attached.

Cmn
Boolean

Indicates that the node is attached to a androidx.compose.ui.layout.Layout which is part of the UI tree.

Cmn
final Modifier.Node

A reference of the Modifier.Node that holds this node's position in the node hierarchy.

Cmn
open Boolean

If this property returns true, then nodes will be automatically invalidated after the modifier update completes (For example, if the returned Node is a DrawModifierNode, its DrawModifierNode.invalidateDraw function will be invoked automatically as part of auto invalidation).

Cmn

Inherited functions

From androidx.compose.ui.node.DelegatableNode
open Unit

Invoked when the density changes for this node.

Cmn
open Unit

Invoked when the layout direction changes for this node.

Cmn

Public constructors

Node

Node()

Public functions

onAttach

open fun onAttach(): Unit

Called when the node is attached to a androidx.compose.ui.layout.Layout which is part of the UI tree. When called, node is guaranteed to be non-null. You can call sideEffect, coroutineScope, etc. This is not guaranteed to get called at a time where the rest of the Modifier.Nodes in the hierarchy are "up to date". For instance, at the time of calling onAttach for this node, another node may be in the tree that will be detached by the time Compose has finished applying changes. As a result, if you need to guarantee that the state of the tree is "final" for this round of changes, you should use the sideEffect API to schedule the calculation to be done at that time.

onDetach

open fun onDetach(): Unit

Called when the node is not attached to a androidx.compose.ui.layout.Layout which is not a part of the UI tree anymore. Note that the node can be reattached again.

This should be called right before the node gets removed from the list, so you should still be able to traverse inside of this method. Ideally we would not allow you to trigger side effects here.

onReset

open fun onReset(): Unit

Called when the node is about to be moved to a pool of layouts ready to be reused. For example it happens when the node is part of the item of LazyColumn after this item is scrolled out of the viewport. This means this node could be in future reused for a androidx.compose.ui.layout.Layout displaying a semantically different content when the list will be populating a new item.

Use this callback to reset some local item specific state, like "is my component focused".

This callback is called while the node is attached. Right after this callback the node will be detached and later reattached when reused.

import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier

class SelectableNode : Modifier.Node() {
    var selected by mutableStateOf(false)

    override fun onReset() {
        // reset `selected` to the initial value as if the node will be reused for
        // displaying different content it shouldn't be selected straight away.
        selected = false
    }

    // some logic which sets `selected` to true when it is selected
}

sideEffect

fun sideEffect(effect: () -> Unit): Unit

This can be called to register effect as a function to be executed after all of the changes to the tree are applied.

This API can only be called if the node isAttached.

Public properties

coroutineScope

val coroutineScopeCoroutineScope

A CoroutineScope that can be used to launch tasks that should run while the node is attached.

The scope is accessible between onAttach and onDetach calls, and will be cancelled after the node is detached (after onDetach returns).

import androidx.compose.animation.core.Animatable
import androidx.compose.ui.Modifier

class AnimatedNode : Modifier.Node() {
    val animatable = Animatable(0f)

    override fun onAttach() {
        coroutineScope.launch { animatable.animateTo(1f) }
    }
}
Throws
kotlin.IllegalStateException

If called while the node is not attached.

isAttached

val isAttachedBoolean

Indicates that the node is attached to a androidx.compose.ui.layout.Layout which is part of the UI tree. This will get set to true right before onAttach is called, and set to false right after onDetach is called.

See also
onAttach
onDetach

node

final val nodeModifier.Node

A reference of the Modifier.Node that holds this node's position in the node hierarchy. If the node is a delegate of another node, this will point to the root delegating node that is actually part of the node tree. Otherwise, this will point to itself.

shouldAutoInvalidate

open val shouldAutoInvalidateBoolean

If this property returns true, then nodes will be automatically invalidated after the modifier update completes (For example, if the returned Node is a DrawModifierNode, its DrawModifierNode.invalidateDraw function will be invoked automatically as part of auto invalidation).

This is enabled by default, and provides a convenient mechanism to schedule invalidation and apply changes made to the modifier. You may choose to set this to false if your modifier has auto-invalidatable properties that do not frequently require invalidation to improve performance by skipping unnecessary invalidation. If autoInvalidate is set to false, you must call the appropriate invalidate functions manually when the modifier is updated or else the updates may not be reflected in the UI appropriately.