ComposeNode
Composable Function
Common
@Composable
public inline fun <T : Any, reified E : Applier<*>> ComposeNode(
noinline factory: () -> T,
update: @DisallowComposableCalls Updater<T>.() -> 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
.
Parameters
factory | A function which will create a new instance of T . This function is NOT guaranteed to be called in place. |
update | 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. |
Common
@Composable
public inline fun <T : Any?, reified E : Applier<*>> ComposeNode(
noinline factory: () -> T,
update: @DisallowComposableCalls Updater<T>.() -> Unit,
content: @Composable () -> 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
.
Parameters
factory | A function which will create a new instance of T . This function is NOT guaranteed to be called in place. |
update | 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 | the composable content that will emit the "children" of this node. |
Common
@Composable
@ExplicitGroupsComposable
public inline fun <T, reified 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
. 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
.
Parameters
factory | A function which will create a new instance of T . This function is NOT guaranteed to be called in place. |
update | 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. |
skippableUpdate | 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 | the composable content that will emit the "children" of this node. |
Code Examples
CustomTreeComposition
@Suppress("unused")
fun CustomTreeComposition() {
// 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++ }
}
}
}
}