# DelegatingNode

Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/node/DelegatingNode.kt+class:androidx.compose.ui.node.DelegatingNode) Added in [1.3.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.3.0) Common/AllAndroid/JVM
- Cmn

  ```
  abstract class DelegatingNode : Modifier.Node
  ```

|---|---|---|
| [kotlin.Any](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html) |||
| ↳ | [androidx.compose.ui.Modifier.Node](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node) ||
|   | ↳ | [androidx.compose.ui.node.DelegatingNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode) |

*** ** * ** ***

A `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` which is able to delegate work to other `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` instances.

This can be useful to compose multiple node implementations into one.

```kotlin
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.PointerInputModifierNode
import androidx.compose.ui.node.SemanticsModifierNode
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.unit.IntSize

class TapGestureNode(var onTap: () -> Unit) : PointerInputModifierNode, Modifier.Node() {
    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize,
    ) {
        // ...
    }

    override fun onCancelPointerInput() {
        // ...
    }
}
class TapGestureWithClickSemantics(onTap: () -> Unit) :
    PointerInputModifierNode, SemanticsModifierNode, DelegatingNode() {
    var onTap: () -> Unit
        get() = gesture.onTap
        set(value) {
            gesture.onTap = value
        }

    val gesture = delegate(TapGestureNode(onTap))

    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize,
    ) {
        gesture.onPointerEvent(pointerEvent, pass, bounds)
    }

    override fun onCancelPointerInput() {
        gesture.onCancelPointerInput()
    }

    override fun SemanticsPropertyReceiver.applySemantics() {
        onClick {
            gesture.onTap()
            true
        }
    }
}
```

```kotlin
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.PointerInputModifierNode
import androidx.compose.ui.node.SemanticsModifierNode
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.unit.IntSize

class TapGestureNode(var onTap: () -> Unit) : PointerInputModifierNode, Modifier.Node() {
    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize,
    ) {
        // ...
    }

    override fun onCancelPointerInput() {
        // ...
    }
}

class TapSemanticsNode(var onTap: () -> Unit) : SemanticsModifierNode, Modifier.Node() {
    override fun SemanticsPropertyReceiver.applySemantics() {
        onClick {
            onTap()
            true
        }
    }
}
class TapGestureWithClickSemantics(onTap: () -> Unit) : DelegatingNode() {
    var onTap: () -> Unit
        get() = gesture.onTap
        set(value) {
            gesture.onTap = value
            semantics.onTap = value
        }

    val gesture = delegate(TapGestureNode(onTap))
    val semantics = delegate(TapSemanticsNode(onTap))
}
```

```kotlin
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.GlobalPositionAwareModifierNode
import androidx.compose.ui.node.PointerInputModifierNode
import androidx.compose.ui.node.SemanticsModifierNode
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.unit.IntSize

class ExpensivePositionHandlingOnPointerEvents : PointerInputModifierNode, DelegatingNode() {

    val globalAwareNode =
        object : GlobalPositionAwareModifierNode, Modifier.Node() {
            override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
                // ...
            }
        }

    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize,
    ) {
        // wait until first pointer event to start listening to global
        // position
        if (!globalAwareNode.isAttached) {
            delegate(globalAwareNode)
        }
        // normal input processing
    }

    override fun onCancelPointerInput() {
        // ...
    }
}

class TapGestureNode(var onTap: () -> Unit) : PointerInputModifierNode, Modifier.Node() {
    override fun onPointerEvent(
        pointerEvent: PointerEvent,
        pass: PointerEventPass,
        bounds: IntSize,
    ) {
        // ...
    }

    override fun onCancelPointerInput() {
        // ...
    }
}

class TapSemanticsNode(var onTap: () -> Unit) : SemanticsModifierNode, Modifier.Node() {
    override fun SemanticsPropertyReceiver.applySemantics() {
        onClick {
            onTap()
            true
        }
    }
}
class TapGestureWithClickSemantics(onTap: () -> Unit) : DelegatingNode() {
    var onTap: () -> Unit
        get() = gesture.onTap
        set(value) {
            gesture.onTap = value
            semantics.onTap = value
        }

    val gesture = delegate(TapGestureNode(onTap))
    val semantics = delegate(TapSemanticsNode(onTap))
}
```

```kotlin
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.GlobalPositionAwareModifierNode

class MyModifierNode(global: Boolean) : DelegatingNode() {
    val globalAwareNode =
        object : GlobalPositionAwareModifierNode, Modifier.Node() {
                override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
                    // ...
                }
            }
            .also { if (global) delegate(it) }
    var global: Boolean = global
        set(value) {
            if (global && !value) {
                undelegate(globalAwareNode)
            } else if (!global && value) {
                delegate(globalAwareNode)
            }
            field = value
        }
}
```

```kotlin
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.GlobalPositionAwareModifierNode
import androidx.compose.ui.node.requireLayoutDirection
import androidx.compose.ui.unit.LayoutDirection

class MyModifierNode : DelegatingNode() {
    val globalAwareNode =
        object : GlobalPositionAwareModifierNode, Modifier.Node() {
            override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
                // ...
            }
        }

    override fun onAttach() {
        // one can conditionally delegate in attach, for instance if certain conditions are met
        if (requireLayoutDirection() == LayoutDirection.Rtl) {
            delegate(globalAwareNode)
        }
    }
}
```

| See also |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode` |   |

## Summary

| ### Public constructors |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#DelegatingNode()()` | Cmn |

| ### Protected functions |
|---|---|---|
| `T` | `<T : https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode> https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)(delegatableNode: T)` In order to properly delegate work to another `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node`, the delegated instance must be created and returned inside of a `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` call. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#undelegate(androidx.compose.ui.node.DelegatableNode)(instance: https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode)` This function expects a node which was passed in to `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` for this node, and is currently being delegated to to be passed in as `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#undelegate(androidx.compose.ui.node.DelegatableNode)`. | Cmn |

### Inherited functions

From [androidx.compose.ui.node.DelegatableNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode) `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onDensityChange()()`

Invoked when the density changes for this node.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onLayoutDirectionChange()()`

Invoked when the layout direction changes for this node.
Cmn From [androidx.compose.ui.Modifier.Node](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node) `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onAttach()()`

Called when the node is attached to a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Layout.composable#Layout(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.ui.layout.MeasurePolicy)` which is part of the UI tree.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onDetach()()`

Called when the node is not attached to a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Layout.composable#Layout(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.ui.layout.MeasurePolicy)` which is not a part of the UI tree anymore.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onReset()()`

Called when the node is about to be moved to a pool of layouts ready to be reused.
Cmn `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#sideEffect(kotlin.Function0)(effect: () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html)`

This can be called to register `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#sideEffect(kotlin.Function0)` as a function to be executed after all of the changes to the tree are applied.
Cmn

### Inherited properties

From [androidx.compose.ui.Modifier.Node](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node) `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#coroutineScope()`

A `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html` that can be used to launch tasks that should run while the node is attached.
Cmn `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#isAttached()`

Indicates that the node is attached to a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Layout.composable#Layout(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.ui.layout.MeasurePolicy)` which is part of the UI tree.
Cmn `final https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#node()`

A reference of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` that holds this node's position in the node hierarchy.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#shouldAutoInvalidate()`

If this property returns `true`, then nodes will be automatically invalidated after the modifier update completes (For example, if the returned Node is a `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DrawModifierNode`, its `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.DrawModifierNode).invalidateDraw()` function will be invoked automatically as part of auto invalidation).
Cmn

## Public constructors

### DelegatingNode

Cmn Added in [1.3.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.3.0)

```
DelegatingNode()
```

## Protected functions

### delegate

Cmn Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0)

```
protected fun <T : DelegatableNode> delegate(delegatableNode: T): T
```

In order to properly delegate work to another `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node`, the delegated instance must be created and returned inside of a `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` call. Doing this will ensure that the created node instance follows all of the right lifecycles and is properly discoverable in this position of the node tree.

By using `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)`, the `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` parameter is returned from this function for convenience.

This method can be called from within an `init` block, however the returned delegated node will not be attached until the delegating node is attached. If `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` is called after the delegating node is already attached, the returned delegated node will be attached.

### undelegate

Cmn Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0)

```
protected fun undelegate(instance: DelegatableNode): Unit
```

This function expects a node which was passed in to `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)` for this node, and is currently being delegated to to be passed in as `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#undelegate(androidx.compose.ui.node.DelegatableNode)`. After this function returns, the node will no longer be attached, and will not be an active delegate of this node.

If `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#undelegate(androidx.compose.ui.node.DelegatableNode)` is not an active delegate of this node, this function will throw an `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-illegal-state-exception/index.html`.