{"id":16202304,"url":"https://github.com/dingyi222666/treeview","last_synced_at":"2025-04-05T16:05:08.318Z","repository":{"id":65289150,"uuid":"583413381","full_name":"dingyi222666/TreeView","owner":"dingyi222666","description":"An Android TreeView with RecyclerView","archived":false,"fork":false,"pushed_at":"2024-11-28T15:27:58.000Z","size":7805,"stargazers_count":122,"open_issues_count":3,"forks_count":12,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-29T15:04:26.136Z","etag":null,"topics":["android","android-library","android-treeview","android-view","expandable","expandablerecyclerview","kotlin","recyclerview","recyclerview-adapter","tree-structure","trees","treeview"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dingyi222666.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-29T17:50:09.000Z","updated_at":"2025-03-14T17:16:19.000Z","dependencies_parsed_at":"2024-01-07T17:11:33.691Z","dependency_job_id":"12348945-932a-418c-b34e-b5a615f71626","html_url":"https://github.com/dingyi222666/TreeView","commit_stats":{"total_commits":69,"total_committers":3,"mean_commits":23.0,"dds":0.02898550724637683,"last_synced_commit":"1706aca5112f2760c20a0f3f5ad2f3b73a4def42"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dingyi222666%2FTreeView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dingyi222666%2FTreeView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dingyi222666%2FTreeView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dingyi222666%2FTreeView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dingyi222666","download_url":"https://codeload.github.com/dingyi222666/TreeView/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247361617,"owners_count":20926642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-library","android-treeview","android-view","expandable","expandablerecyclerview","kotlin","recyclerview","recyclerview-adapter","tree-structure","trees","treeview"],"created_at":"2024-10-10T09:46:53.285Z","updated_at":"2025-04-05T16:05:08.276Z","avatar_url":"https://github.com/dingyi222666.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"## TreeView\n\n## Maintainers Needed！See [#12](https://github.com/dingyi222666/TreeView/issues/12) for more details.\n\nAn TreeView implement in Android with RecyclerView written in kotlin.\n\n[![CI Build Status](https://github.com/dingyi222666/TreeView/actions/workflows/android.yml/badge.svg)](https://github.com/dingyi222666/TreeView/tree/main/.github/workflows/android.yml)\n![maven-central](https://img.shields.io/maven-central/v/io.github.dingyi222666/treeview.svg)\n[![GitHub license](https://img.shields.io/github/license/dingyi222666/TreeView)](https://github.com/dingyi222666/TreeView/blob/main/LICENSE)\n\n## Features\n\n1. 100% written in kotlin.\n2. Customise, ~~in the future~~ you can implement your own tree data structure.\n3. Fetching data asynchronously(Lazy load), no need to load all data at once.\n4. Horizontal scroll support. ~~(with bug)~~\n5. Built-in DSL\n\n## Screenshot\n\n![output.webp](./screenshots/main.webp)\n![output.webp](./screenshots/main_2.webp)\n\n## TODO\n\n- [x] Select or Deselect Node\n- [x] Better TreeNodeGenerator API\n- [ ] More API to operate the node in the tree, such as expand, collapse, etc.\n- [x] Draggable nodes\n\n## Usage\n\n- Add the dependency to your gradle file\n\n```groovy\nimplementation(\"io.github.dingyi222666:treeview:1.3.3\")\n```\n\n- Use the `DataSource` DSL to create tree used for the TreeView. Also you can [use the `TreeNodeGenerator`](https://github.com/dingyi222666/TreeView/issues/4) to create the tree.\n\n```kotlin\nprivate fun createTree(): Tree\u003cDataSource\u003cString\u003e\u003e {\n    val dataCreator: CreateDataScope\u003cString\u003e = { _, _ -\u003e UUID.randomUUID().toString() }\n    return buildTree(dataCreator) {\n        Branch(\"app\") {\n            Branch(\"src\") {\n                Branch(\"main\") {\n                    Branch(\"java\") {\n                        Branch(\"com.dingyi.treeview\") {\n                            Leaf(\"MainActivity.kt\")\n                        }\n                    }\n                    Branch(\"res\") {\n                        Branch(\"drawable\") {\n\n                        }\n                        Branch(\"xml\") {}\n                    }\n                    Leaf(\"AndroidManifest.xml\")\n                }\n            }\n        }\n    }\n}\n```\n\n- Create a node binder to bind the node to the layout, and in most case also implement node click\n  events in this class\n\n  Note: For the indentation setting of the item, we recommend using a Space widget placed at the visual leftmost of your item layout. \n- The width of this widget is the indentation width of the item.\n\n```kotlin\ninner class ViewBinder : TreeViewBinder\u003cDataSource\u003cString\u003e\u003e(),\n    TreeNodeEventListener\u003cDataSource\u003cString\u003e\u003e {\n\n    override fun createView(parent: ViewGroup, viewType: Int): View {\n        return if (viewType == 1) {\n            ItemDirBinding.inflate(layoutInflater, parent, false).root\n        } else {\n            ItemFileBinding.inflate(layoutInflater, parent, false).root\n        }\n    }\n\n    override fun getItemViewType(node: TreeNode\u003cDataSource\u003cString\u003e\u003e): Int {\n        if (node.isChild) {\n            return 1\n        }\n        return 0\n    }\n\n    override fun bindView(\n        holder: TreeView.ViewHolder,\n        node: TreeNode\u003cDataSource\u003cString\u003e\u003e,\n        listener: TreeNodeEventListener\u003cDataSource\u003cString\u003e\u003e\n    ) {\n        if (node.isChild) {\n            applyDir(holder, node)\n        } else {\n            applyFile(holder, node)\n        }\n\n        val itemView = holder.itemView.findViewById\u003cSpace\u003e(R.id.space)\n\n        itemView.updateLayoutParams\u003cViewGroup.MarginLayoutParams\u003e {\n            width = node.depth * 22.dp\n        }\n\n    }\n\n    private fun applyFile(holder: TreeView.ViewHolder, node: TreeNode\u003cDataSource\u003cString\u003e\u003e) {\n        val binding = ItemFileBinding.bind(holder.itemView)\n        binding.tvName.text = node.name.toString()\n    }\n\n    private fun applyDir(holder: TreeView.ViewHolder, node: TreeNode\u003cDataSource\u003cString\u003e\u003e) {\n        val binding = ItemDirBinding.bind(holder.itemView)\n        binding.tvName.text = node.name.toString()\n\n        binding\n            .ivArrow\n            .animate()\n            .rotation(if (node.expand) 90f else 0f)\n            .setDuration(200)\n            .start()\n    }\n\n\n    override fun onClick(node: TreeNode\u003cDataSource\u003cString\u003e\u003e, holder: TreeView.ViewHolder) {\n        if (node.isChild) {\n            applyDir(holder, node)\n        } else {\n            Toast.makeText(this@MainActivity, \"Clicked ${node.name}\", Toast.LENGTH_LONG).show()\n        }\n    }\n\n    override fun onToggle(\n        node: TreeNode\u003cDataSource\u003cString\u003e\u003e,\n        isExpand: Boolean,\n        holder: TreeView.ViewHolder\n    ) {\n        applyDir(holder, node)\n    }\n}\n\n```\n\n- If you want to implement horizontal scrolling, you need to set the `supportHorizontalScroll` to\n  true\n\n```kotlin\ntreeview.supportHorizontalScroll = true\n```\n\n- Now you can create the tree structure and set up the node generator and node binder for the\n  TreeView, and then call `refresh()` to load the data\n\n```kotlin\n val tree = createTree()\n\n(binding.treeview as TreeView\u003cDataSource\u003cString\u003e\u003e).apply {\n    bindCoroutineScope(lifecycleScope)\n    this.tree = tree\n    binder = ViewBinder()\n    nodeEventListener = binder\n}\n\nlifecycleScope.launch {\n    binding.treeview.refresh()\n}\n\n```\n\n- If you want to load dynamic data (etc. local file), you can see this example\n  [here](./app/src/main/kotlin/com/dingyi/treeview/FileActivity.kt)\n\n\n- Done! Enjoy using it.\n\n## Special thanks\n\n- [Rosemoe](https://github.com/Rosemoe) (Help improve the TreeView horizontal scrolling support)\n- [HackerMadCat/Multimap](https://github.com/HackerMadCat/Multimap) (Multimap implementation in\n  kotlin)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdingyi222666%2Ftreeview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdingyi222666%2Ftreeview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdingyi222666%2Ftreeview/lists"}