dingyi222666 / TreeView

An Android TreeView with RecyclerView
Apache License 2.0
107 stars 10 forks source link
android android-library android-treeview android-view expandable expandablerecyclerview kotlin recyclerview recyclerview-adapter tree-structure trees treeview

TreeView

Maintainers Needed!See #12 for more details.

An TreeView implement in Android with RecyclerView written in kotlin.

CI Build Status maven-central GitHub license

Features

  1. 100% written in kotlin.
  2. Customise, in the future you can implement your own tree data structure.
  3. Fetching data asynchronously(Lazy load), no need to load all data at once.
  4. Horizontal scroll support. (with bug)
  5. Built-in DSL

Screenshot

output.webp output.webp

TODO

Usage

implementation("io.github.dingyi222666:treeview:1.3.1")
private fun createTree(): Tree<DataSource<String>> {
    val dataCreator: CreateDataScope<String> = { _, _ -> UUID.randomUUID().toString() }
    return buildTree(dataCreator) {
        Branch("app") {
            Branch("src") {
                Branch("main") {
                    Branch("java") {
                        Branch("com.dingyi.treeview") {
                            Leaf("MainActivity.kt")
                        }
                    }
                    Branch("res") {
                        Branch("drawable") {

                        }
                        Branch("xml") {}
                    }
                    Leaf("AndroidManifest.xml")
                }
            }
        }
    }
}
inner class ViewBinder : TreeViewBinder<DataSource<String>>(),
    TreeNodeEventListener<DataSource<String>> {

    override fun createView(parent: ViewGroup, viewType: Int): View {
        return if (viewType == 1) {
            ItemDirBinding.inflate(layoutInflater, parent, false).root
        } else {
            ItemFileBinding.inflate(layoutInflater, parent, false).root
        }
    }

    override fun getItemViewType(node: TreeNode<DataSource<String>>): Int {
        if (node.isChild) {
            return 1
        }
        return 0
    }

    override fun bindView(
        holder: TreeView.ViewHolder,
        node: TreeNode<DataSource<String>>,
        listener: TreeNodeEventListener<DataSource<String>>
    ) {
        if (node.isChild) {
            applyDir(holder, node)
        } else {
            applyFile(holder, node)
        }

        val itemView = holder.itemView.findViewById<Space>(R.id.space)

        itemView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            width = node.depth * 22.dp
        }

    }

    private fun applyFile(holder: TreeView.ViewHolder, node: TreeNode<DataSource<String>>) {
        val binding = ItemFileBinding.bind(holder.itemView)
        binding.tvName.text = node.name.toString()
    }

    private fun applyDir(holder: TreeView.ViewHolder, node: TreeNode<DataSource<String>>) {
        val binding = ItemDirBinding.bind(holder.itemView)
        binding.tvName.text = node.name.toString()

        binding
            .ivArrow
            .animate()
            .rotation(if (node.expand) 90f else 0f)
            .setDuration(200)
            .start()
    }

    override fun onClick(node: TreeNode<DataSource<String>>, holder: TreeView.ViewHolder) {
        if (node.isChild) {
            applyDir(holder, node)
        } else {
            Toast.makeText(this@MainActivity, "Clicked ${node.name}", Toast.LENGTH_LONG).show()
        }
    }

    override fun onToggle(
        node: TreeNode<DataSource<String>>,
        isExpand: Boolean,
        holder: TreeView.ViewHolder
    ) {
        applyDir(holder, node)
    }
}
treeview.supportHorizontalScroll = true
 val tree = createTree()

(binding.treeview as TreeView<DataSource<String>>).apply {
    bindCoroutineScope(lifecycleScope)
    this.tree = tree
    binder = ViewBinder()
    nodeEventListener = binder
}

lifecycleScope.launch {
    binding.treeview.refresh()
}

Special thanks