mirror of
				https://github.com/AdrianKuta/Expandable-RecyclerView.git
				synced 2025-10-31 17:03:39 +01:00 
			
		
		
		
	Improved function for finding not collapsed nodes.
This commit is contained in:
		| @@ -15,7 +15,7 @@ android { | |||||||
|         minSdkVersion 23 |         minSdkVersion 23 | ||||||
|         targetSdkVersion 29 |         targetSdkVersion 29 | ||||||
|         versionCode 1 |         versionCode 1 | ||||||
|         versionName "0.0.1-alpha02" |         versionName "0.0.1-beta01" | ||||||
|  |  | ||||||
|         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||||||
|         consumerProguardFiles 'consumer-rules.pro' |         consumerProguardFiles 'consumer-rules.pro' | ||||||
|   | |||||||
| @@ -6,33 +6,77 @@ import com.github.adriankuta.datastructure.tree.TreeNode | |||||||
| class ExpandableTreeNode<T>(value: T) : TreeNode<T>(value) { | class ExpandableTreeNode<T>(value: T) : TreeNode<T>(value) { | ||||||
|  |  | ||||||
|     var expanded: Boolean = true |     var expanded: Boolean = true | ||||||
|         set(value) { |  | ||||||
|             field = value |  | ||||||
|             children.forEach { |  | ||||||
|                 (it as ExpandableTreeNode).expanded = value |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override fun child(value: T, childDeclaration: ChildDeclaration<T>?) { |     override fun child(child: T, childDeclaration: ChildDeclaration<T>?) { | ||||||
|         val newChild = ExpandableTreeNode(value) |         val newChild = ExpandableTreeNode(child) | ||||||
|         if (childDeclaration != null) |         if (childDeclaration != null) | ||||||
|             newChild.childDeclaration() |             newChild.childDeclaration() | ||||||
|         addChild(newChild) |         addChild(newChild) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getVisibleNodeCount(): Int { |     /** | ||||||
|         return onlyVisibleItems() |      * @param skipRootNode If `True`, then root node won't be counted. | ||||||
|  |      */ | ||||||
|  |     internal fun getVisibleNodeCount(skipRootNode: Boolean): Int { | ||||||
|  |         var size = onlyVisibleItems() | ||||||
|             .size |             .size | ||||||
|  |  | ||||||
|  |         if (skipRootNode && size > 0) | ||||||
|  |             size-- | ||||||
|  |  | ||||||
|  |         return size | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getVisibleNode(position: Int): ExpandableTreeNode<T> { |     /** | ||||||
|         return onlyVisibleItems()[position] |      * This function use Pre-order iteration to go through tree: | ||||||
|  |      * ``` | ||||||
|  |      * e.g. | ||||||
|  |      *                    1 | ||||||
|  |      *                  / | \ | ||||||
|  |      *                 /  |   \ | ||||||
|  |      *               2    3     4 | ||||||
|  |      *              / \       / | \ | ||||||
|  |      *             5    6    7  8  9 | ||||||
|  |      *            /   / | \ | ||||||
|  |      *           10  11 12 13 | ||||||
|  |      * | ||||||
|  |      * Output (skipRootNode = false): 1 2 5 10 6 11 12 13 3 4 7 8 9 | ||||||
|  |      * Output (skipRootNode = true): 2 5 10 6 11 12 13 3 4 7 8 9 | ||||||
|  |      * ``` | ||||||
|  |      * @param skipRootNode If `True` root element will be omitted, and position 0 will be for first left child. | ||||||
|  |      */ | ||||||
|  |     internal fun getVisibleNode(position: Int, skipRootNode: Boolean): ExpandableTreeNode<T> { | ||||||
|  |         val nodePosition = if (skipRootNode) position + 1 else position | ||||||
|  |         return onlyVisibleItems()[nodePosition] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return List of nodes which parent or higher ancestor aren't collapsed. | ||||||
|  |      */ | ||||||
|     private fun onlyVisibleItems(): List<ExpandableTreeNode<T>> { |     private fun onlyVisibleItems(): List<ExpandableTreeNode<T>> { | ||||||
|         //Visible if parent of node is expanded. |         //Visible if parent of node is expanded. | ||||||
|         return map { it as ExpandableTreeNode } |         return map { it as ExpandableTreeNode } | ||||||
|             .filter { (it.parent as? ExpandableTreeNode)?.expanded ?: true } |             .filter { allAncestorsAreExpanded(it) } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * `Ancestor` is a node reachable by repeated proceeding from child to parent. | ||||||
|  |      * @return `True` if parent, and all parent's ancestors are expanded. | ||||||
|  |      */ | ||||||
|  |     private fun allAncestorsAreExpanded(node: ExpandableTreeNode<T>): Boolean { | ||||||
|  |         var ancestor = parent as? ExpandableTreeNode | ||||||
|  |         var ancestorsAreExpanded = isAncestorExpanded(ancestor) | ||||||
|  |  | ||||||
|  |         while (ancestorsAreExpanded && ancestor != null) { | ||||||
|  |             ancestor = ancestor.parent as? ExpandableTreeNode<T> | ||||||
|  |             ancestorsAreExpanded = ancestorsAreExpanded.and(isAncestorExpanded(ancestor)) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return ancestorsAreExpanded | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun isAncestorExpanded(ancestor: ExpandableTreeNode<T>?): Boolean { | ||||||
|  |         return ancestor?.expanded ?: true | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -12,25 +12,35 @@ abstract class MultilevelRecyclerViewAdapter<T, VH : RecyclerView.ViewHolder> : | |||||||
|     abstract override fun onCreateViewHolder(parent: ViewGroup, nestLevel: Int): VH |     abstract override fun onCreateViewHolder(parent: ViewGroup, nestLevel: Int): VH | ||||||
|  |  | ||||||
|     final override fun onBindViewHolder(holder: VH, position: Int) { |     final override fun onBindViewHolder(holder: VH, position: Int) { | ||||||
|         onBindViewHolder(holder, treeNodes.getVisibleNode(position)) |         val visibleNode = treeNodes.getVisibleNode(position, true) | ||||||
|  |         onBindViewHolder(holder, visibleNode, visibleNode.depth()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     abstract fun onBindViewHolder(holder: VH, treeNode: ExpandableTreeNode<T>) |     abstract fun onBindViewHolder(holder: VH, treeNode: ExpandableTreeNode<T>, nestLevel: Int) | ||||||
|  |  | ||||||
|     abstract fun getTreeNodes(): ExpandableTreeNode<T> |     abstract fun getTreeNodes(): ExpandableTreeNode<T> | ||||||
|  |  | ||||||
|     final override fun getItemCount(): Int { |     final override fun getItemCount(): Int { | ||||||
|         treeNodes = getTreeNodes() |         treeNodes = getTreeNodes() | ||||||
|         return treeNodes.getVisibleNodeCount() |         return treeNodes.getVisibleNodeCount(true) //We don't want to show root element. | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final override fun getItemViewType(position: Int): Int { |     final override fun getItemViewType(position: Int): Int { | ||||||
|  |         return treeNodes.getVisibleNode(position, true).depth() | ||||||
|         return treeNodes.getVisibleNode(position).depth() |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun toggleGroup(expandableTreeNode: ExpandableTreeNode<T>) { |     fun toggleGroup(expandableTreeNode: ExpandableTreeNode<T>) { | ||||||
|         expandableTreeNode.expanded = !expandableTreeNode.expanded |         expandableTreeNode.expanded = !expandableTreeNode.expanded | ||||||
|         notifyDataSetChanged() |         notifyDataSetChanged() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun expand(expandableTreeNode: ExpandableTreeNode<T>) { | ||||||
|  |         expandableTreeNode.expanded = true | ||||||
|  |         notifyDataSetChanged() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun collapse(expandableTreeNode: ExpandableTreeNode<T>) { | ||||||
|  |         expandableTreeNode.expanded = false | ||||||
|  |         notifyDataSetChanged() | ||||||
|  |     } | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user