ControlledComposition

Function

Common
@TestOnly
public fun ControlledComposition(
    applier: Applier<*>,
    parent: CompositionContext,
): ControlledComposition

This method is a way to initiate a composition. Optionally, a parent CompositionContext can be provided to make the composition behave as a sub-composition of the parent or a Recomposer can be provided.

A controlled composition allows direct control of the composition instead of it being controlled by the Recomposer passed ot the root composition.

It is important to call Composition.dispose this composer is no longer needed in order to release resources.

Parameters

applierThe Applier instance to be used in the composition.
parentThe parent CompositionContext.
Common
@TestOnly
@ExperimentalComposeApi
public fun ControlledComposition(
    applier: Applier<*>,
    parent: CompositionContext,
    recomposeCoroutineContext: CoroutineContext,
): ControlledComposition

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++ }
            }
        }
    }
}