DelegatingNode
-
Cmn
abstract class DelegatingNode : Modifier.Node
A Modifier.Node which is able to delegate work to other Modifier.Node instances.
This can be useful to compose multiple node implementations into one.
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 } } }
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)) }
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)) }
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 } }
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 | |
|---|---|
DelegatingNode |
Summary
Public constructors |
|
|---|---|
|
Cmn
|
Protected functions |
||
|---|---|---|
T |
<T : DelegatableNode> delegate(delegatableNode: T)In order to properly delegate work to another |
Cmn
|
Unit |
undelegate(instance: DelegatableNode)This function expects a node which was passed in to |
Cmn
|
Inherited functions |
||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Inherited properties |
||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Public constructors
Protected functions
delegate
protected fun <T : DelegatableNode> delegate(delegatableNode: T): T
In order to properly delegate work to another Modifier.Node, the delegated instance must be created and returned inside of a delegate 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 delegate, the 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 delegate is called after the delegating node is already attached, the returned delegated node will be attached.
undelegate
protected fun undelegate(instance: DelegatableNode): Unit
This function expects a node which was passed in to delegate for this node, and is currently being delegated to to be passed in as instance. After this function returns, the node will no longer be attached, and will not be an active delegate of this node.
If instance is not an active delegate of this node, this function will throw an IllegalStateException.