I want to create a tree layout dynamically using constraint layout.
Something like this:
With tree child nodes retrieved at runtime.
Specifications:
1. All nodes can have a maximum of three child nodes.
2. The whole layout must be created programmatically.
3. Null is passed in data if a node does not have a child.
What I tried:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
createTree(treeNode)
}
private fun createTree(treeNode: TreeNode) {
val rootView: ConstraintLayout = dataBinding.root as ConstraintLayout
val treeView = createLayout(treeNode, 0)
if (treeView != null) {
val mainViewConstraintSet = ConstraintSet()
mainViewConstraintSet.clone(treeView)
mainViewConstraintSet.connect(
rootView.id,
ConstraintSet.START,
treeView.id,
ConstraintSet.START
)
mainViewConstraintSet.connect(
rootView.id,
ConstraintSet.END,
treeView.id,
ConstraintSet.END
)
mainViewConstraintSet.applyTo(treeView)
rootView.addView(treeView)
Log.e("Log", "Added Root View")
}
}
private fun createLayout(treeNode: TreeNode?, depth: Int): ConstraintLayout? {
if (depth > 1) {
return null
}
if (treeNode == null) {
return null
}
val layoutView = ConstraintLayout(context)
val layoutViewLayoutParams = ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
layoutViewLayoutParams.topMargin = 16
layoutViewLayoutParams.leftMargin = 16
layoutViewLayoutParams.rightMargin = 16
layoutViewLayoutParams.bottomMargin = 16
layoutView.layoutParams = layoutViewLayoutParams
layoutView.setBackgroundColor(Color.CYAN)
layoutView.id = ViewCompat.generateViewId()
val layoutNode = createNode(treeNode.user)
Log.e("Log", "Created node for " + treeNode.user.name)
val leftChildLayout = createLayout(treeNode.left, depth + 1)
val middleChildLayout = createLayout(treeNode.middle, depth + 1)
val rightChildLayout = createLayout(treeNode.right, depth + 1)
val mainViewConstraintSet = ConstraintSet()
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.TOP,
layoutView.id,
ConstraintSet.TOP,
16
)
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.BOTTOM,
layoutView.id,
ConstraintSet.BOTTOM,
16
)
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.START,
layoutView.id,
ConstraintSet.START,
16
)
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.END,
layoutView.id,
ConstraintSet.END,
16
)
if (leftChildLayout != null) {
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.BOTTOM,
leftChildLayout.id,
ConstraintSet.TOP,
16
)
}
if (middleChildLayout != null) {
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.BOTTOM,
middleChildLayout.id,
ConstraintSet.TOP,
16
)
}
if (rightChildLayout != null) {
mainViewConstraintSet.connect(
layoutNode.id,
ConstraintSet.BOTTOM,
rightChildLayout.id,
ConstraintSet.TOP,
16
)
}
if (leftChildLayout != null && middleChildLayout != null) {
mainViewConstraintSet.connect(
leftChildLayout.id,
ConstraintSet.END,
middleChildLayout.id,
ConstraintSet.START,
16
)
mainViewConstraintSet.connect(
middleChildLayout.id,
ConstraintSet.END,
leftChildLayout.id,
ConstraintSet.START,
16
)
}
if (rightChildLayout != null && middleChildLayout != null) {
mainViewConstraintSet.connect(
middleChildLayout.id,
ConstraintSet.END,
rightChildLayout.id,
ConstraintSet.START,
16
)
mainViewConstraintSet.connect(
rightChildLayout.id,
ConstraintSet.END,
middleChildLayout.id,
ConstraintSet.START,
16
)
}
mainViewConstraintSet.applyTo(layoutView)
// layoutView.setConstraintSet(mainViewConstraintSet)
if (leftChildLayout != null) {
layoutView.addView(leftChildLayout)
}
if (middleChildLayout != null) {
layoutView.addView(middleChildLayout)
}
if (rightChildLayout != null) {
layoutView.addView(rightChildLayout)
}
layoutView.addView(layoutNode)
return layoutView
}
private fun createNode(user: User): ConstraintLayout {
val node = ConstraintLayout(context)
node.id = ViewCompat.generateViewId()
val nodeTextView = TextView(context)
nodeTextView.id = ViewCompat.generateViewId()
nodeTextView.text = user.name
nodeTextView.textSize = 18f
nodeTextView.setTextColor(Color.BLACK)
nodeTextView.setTypeface(null, Typeface.BOLD)
val layoutParams = ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT
)
nodeTextView.layoutParams = layoutParams
nodeTextView.setBackgroundColor(Color.GREEN)
val constraintSet = ConstraintSet()
constraintSet.clone(node)
constraintSet.connect(nodeTextView.id, ConstraintSet.TOP, node.id, ConstraintSet.TOP, 16)
constraintSet.connect(nodeTextView.id, ConstraintSet.LEFT, node.id, ConstraintSet.LEFT, 16)
constraintSet.applyTo(node)
node.addView(nodeTextView)
node.setBackgroundColor(Color.RED)
return node
}
The Tree Data Model:
data class TreeNode( val user: User, var parent: TreeNode?,
var left: TreeNode?, var middle: TreeNode?, var right: TreeNode?) { }