[go: nahoru, domu]

blob: cca5ce04e34364921daf91361b22a8ea2bf6bce9 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.runtime.samples
import androidx.annotation.Sampled
import androidx.compose.runtime.AbstractApplier
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.ExperimentalComposeApi
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@Suppress("unused")
@OptIn(ExperimentalComposeApi::class)
@Sampled
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++ }
}
}
}
}