ComposeNode

Functions summary

inline Unit
@Composable
<T : Any, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit
)

Emits a node into the composition of type T.

Cmn
inline Unit
@Composable
<T : Any?, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit,
    content: @Composable () -> Unit
)

Emits a node into the composition of type T.

Cmn
inline Unit
@Composable
@ExplicitGroupsComposable
<T : Any?, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit,
    noinline skippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
    content: @Composable () -> Unit
)

Emits a node into the composition of type T.

Cmn

Functions

ComposeNode

@Composable
inline fun <T : Any, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit
): Unit

Emits a node into the composition of type T.

This function will throw a runtime exception if E is not a subtype of the applier of the currentComposer.

import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

// Provided we have a tree with a node base type like the following
abstract class Node {
    val children = mutableListOf<Node>()
}

// We would implement an Applier class like the following, which would teach compose how to
// manage a tree of Nodes.
class NodeApplier(root: Node) : AbstractApplier<Node>(root) {
    override fun insertTopDown(index: Int, instance: Node) {
        current.children.add(index, instance)
    }

    override fun insertBottomUp(index: Int, instance: Node) {
        // Ignored as the tree is built top-down.
    }

    override fun remove(index: Int, count: Int) {
        current.children.remove(index, count)
    }

    override fun move(from: Int, to: Int, count: Int) {
        current.children.move(from, to, count)
    }

    override fun onClear() {
        root.children.clear()
    }
}

// A function like the following could be created to create a composition provided a root Node.
fun Node.setContent(parent: CompositionContext, content: @Composable () -> Unit): Composition {
    return Composition(NodeApplier(this), parent).apply { setContent(content) }
}

// assuming we have Node sub-classes like "TextNode" and "GroupNode"
class TextNode : Node() {
    var text: String = ""
    var onClick: () -> Unit = {}
}
class GroupNode : Node()

// Composable equivalents could be created
@Composable
fun Text(text: String, onClick: () -> Unit = {}) {
    ComposeNode<TextNode, NodeApplier>(::TextNode) {
        set(text) { this.text = it }
        set(onClick) { this.onClick = it }
    }
}

@Composable
fun Group(content: @Composable () -> Unit) {
    ComposeNode<GroupNode, NodeApplier>(::GroupNode, {}, content)
}

// and then a sample tree could be composed:
fun runApp(root: GroupNode, parent: CompositionContext) {
    root.setContent(parent) {
        var count by remember { mutableStateOf(0) }
        Group {
            Text("Count: $count")
            Text("Increment") { count++ }
        }
    }
}
Parameters
noinline factory: () -> T

A function which will create a new instance of T. This function is NOT guaranteed to be called in place.

update: @DisallowComposableCalls Updater<T>.() -> Unit

A function to perform updates on the node. This will run every time emit is executed. This function is called in place and will be inlined.

ComposeNode

@Composable
inline fun <T : Any?, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit,
    content: @Composable () -> Unit
): Unit

Emits a node into the composition of type T. Nodes emitted inside of content will become children of the emitted node.

This function will throw a runtime exception if E is not a subtype of the applier of the currentComposer.

import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

// Provided we have a tree with a node base type like the following
abstract class Node {
    val children = mutableListOf<Node>()
}

// We would implement an Applier class like the following, which would teach compose how to
// manage a tree of Nodes.
class NodeApplier(root: Node) : AbstractApplier<Node>(root) {
    override fun insertTopDown(index: Int, instance: Node) {
        current.children.add(index, instance)
    }

    override fun insertBottomUp(index: Int, instance: Node) {
        // Ignored as the tree is built top-down.
    }

    override fun remove(index: Int, count: Int) {
        current.children.remove(index, count)
    }

    override fun move(from: Int, to: Int, count: Int) {
        current.children.move(from, to, count)
    }

    override fun onClear() {
        root.children.clear()
    }
}

// A function like the following could be created to create a composition provided a root Node.
fun Node.setContent(parent: CompositionContext, content: @Composable () -> Unit): Composition {
    return Composition(NodeApplier(this), parent).apply { setContent(content) }
}

// assuming we have Node sub-classes like "TextNode" and "GroupNode"
class TextNode : Node() {
    var text: String = ""
    var onClick: () -> Unit = {}
}
class GroupNode : Node()

// Composable equivalents could be created
@Composable
fun Text(text: String, onClick: () -> Unit = {}) {
    ComposeNode<TextNode, NodeApplier>(::TextNode) {
        set(text) { this.text = it }
        set(onClick) { this.onClick = it }
    }
}

@Composable
fun Group(content: @Composable () -> Unit) {
    ComposeNode<GroupNode, NodeApplier>(::GroupNode, {}, content)
}

// and then a sample tree could be composed:
fun runApp(root: GroupNode, parent: CompositionContext) {
    root.setContent(parent) {
        var count by remember { mutableStateOf(0) }
        Group {
            Text("Count: $count")
            Text("Increment") { count++ }
        }
    }
}
Parameters
noinline factory: () -> T

A function which will create a new instance of T. This function is NOT guaranteed to be called in place.

update: @DisallowComposableCalls Updater<T>.() -> Unit

A function to perform updates on the node. This will run every time emit is executed. This function is called in place and will be inlined.

content: @Composable () -> Unit

the composable content that will emit the "children" of this node.

ComposeNode

@Composable
@ExplicitGroupsComposable
inline fun <T : Any?, E : Applier<*>> ComposeNode(
    noinline factory: () -> T,
    update: @DisallowComposableCalls Updater<T>.() -> Unit,
    noinline skippableUpdate: @Composable SkippableUpdater<T>.() -> Unit,
    content: @Composable () -> Unit
): Unit

Emits a node into the composition of type T. Nodes emitted inside of content will become children of the emitted node.

This function will throw a runtime exception if E is not a subtype of the applier of the currentComposer.

import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember

// Provided we have a tree with a node base type like the following
abstract class Node {
    val children = mutableListOf<Node>()
}

// We would implement an Applier class like the following, which would teach compose how to
// manage a tree of Nodes.
class NodeApplier(root: Node) : AbstractApplier<Node>(root) {
    override fun insertTopDown(index: Int, instance: Node) {
        current.children.add(index, instance)
    }

    override fun insertBottomUp(index: Int, instance: Node) {
        // Ignored as the tree is built top-down.
    }

    override fun remove(index: Int, count: Int) {
        current.children.remove(index, count)
    }

    override fun move(from: Int, to: Int, count: Int) {
        current.children.move(from, to, count)
    }

    override fun onClear() {
        root.children.clear()
    }
}

// A function like the following could be created to create a composition provided a root Node.
fun Node.setContent(parent: CompositionContext, content: @Composable () -> Unit): Composition {
    return Composition(NodeApplier(this), parent).apply { setContent(content) }
}

// assuming we have Node sub-classes like "TextNode" and "GroupNode"
class TextNode : Node() {
    var text: String = ""
    var onClick: () -> Unit = {}
}
class GroupNode : Node()

// Composable equivalents could be created
@Composable
fun Text(text: String, onClick: () -> Unit = {}) {
    ComposeNode<TextNode, NodeApplier>(::TextNode) {
        set(text) { this.text = it }
        set(onClick) { this.onClick = it }
    }
}

@Composable
fun Group(content: @Composable () -> Unit) {
    ComposeNode<GroupNode, NodeApplier>(::GroupNode, {}, content)
}

// and then a sample tree could be composed:
fun runApp(root: GroupNode, parent: CompositionContext) {
    root.setContent(parent) {
        var count by remember { mutableStateOf(0) }
        Group {
            Text("Count: $count")
            Text("Increment") { count++ }
        }
    }
}
Parameters
noinline factory: () -> T

A function which will create a new instance of T. This function is NOT guaranteed to be called in place.

update: @DisallowComposableCalls Updater<T>.() -> Unit

A function to perform updates on the node. This will run every time emit is executed. This function is called in place and will be inlined.

noinline skippableUpdate: @Composable SkippableUpdater<T>.() -> Unit

A function to perform updates on the node. Unlike update, this function is Composable and will therefore be skipped unless it has been invalidated by some other mechanism. This can be useful to perform expensive calculations for updating the node where the calculations are likely to have the same inputs over time, so the function's execution can be skipped.

content: @Composable () -> Unit

the composable content that will emit the "children" of this node.