From b3850a542d28cdaa311d9e0829864a66e3583bc9 Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Tue, 21 Jan 2020 23:27:14 +0100 Subject: [PATCH 1/3] sample implementation --- app/build.gradle | 4 + .../github/adriankuta/ExpandableAdapter.kt | 88 +++++++++++++++++++ .../com/github/adriankuta/MainActivity.kt | 28 +++++- .../drawable/ic_expand_less_black_24dp.xml | 9 ++ .../drawable/ic_expand_more_black_24dp.xml | 9 ++ app/src/main/res/drawable/ic_last_element.xml | 18 ++++ .../main/res/drawable/ic_middle_element.xml | 18 ++++ .../main/res/drawable/ic_vertical_line.xml | 13 +++ app/src/main/res/layout/activity_main.xml | 12 +-- app/src/main/res/layout/item_level_1.xml | 38 ++++++++ app/src/main/res/layout/item_level_2.xml | 53 +++++++++++ app/src/main/res/layout/item_level_3.xml | 65 ++++++++++++++ 12 files changed, 348 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt create mode 100644 app/src/main/res/drawable/ic_expand_less_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_expand_more_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_last_element.xml create mode 100644 app/src/main/res/drawable/ic_middle_element.xml create mode 100644 app/src/main/res/drawable/ic_vertical_line.xml create mode 100644 app/src/main/res/layout/item_level_1.xml create mode 100644 app/src/main/res/layout/item_level_2.xml create mode 100644 app/src/main/res/layout/item_level_3.xml diff --git a/app/build.gradle b/app/build.gradle index 0fec2ab..8d17d4f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,6 +21,9 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + dataBinding { + enabled = true + } } dependencies { @@ -29,6 +32,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'com.github.adriankuta:expandable-recyclerView:0.0.1-beta01' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt b/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt new file mode 100644 index 0000000..9cae40c --- /dev/null +++ b/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt @@ -0,0 +1,88 @@ +package com.github.adriankuta + +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.github.adriankuta.databinding.ItemLevel1Binding +import com.github.adriankuta.databinding.ItemLevel2Binding +import com.github.adriankuta.databinding.ItemLevel3Binding +import com.github.adriankuta.expandable_recyclerview.ExpandableTreeNode +import com.github.adriankuta.expandable_recyclerview.MultilevelRecyclerViewAdapter +import com.github.adriankuta.expandable_recyclerview.expandableTree + +class ExpandableAdapter : + MultilevelRecyclerViewAdapter() { + + private var tree: ExpandableTreeNode? = null + + fun setTree(tree: ExpandableTreeNode) { + this.tree = tree + notifyDataSetChanged() + } + + override fun getTreeNodes(): ExpandableTreeNode = tree ?: expandableTree("") {} + + override fun onCreateViewHolder(parent: ViewGroup, nestLevel: Int): ExpandableViewHolder { + return when (nestLevel) { + 1 -> ExpandableViewHolder.Level1(parent.inflateLevel1()) + 2 -> ExpandableViewHolder.Level2(parent.inflateLevel2()) + 3 -> ExpandableViewHolder.Level3(parent.inflateLevel3()) + else -> throw IllegalArgumentException("Not implemented ViewHolder for nest level: $nestLevel") + } + } + + override fun onBindViewHolder( + holder: ExpandableViewHolder, + treeNode: ExpandableTreeNode, + nestLevel: Int + ) { + holder.bind(treeNode, nestLevel) + } + + sealed class ExpandableViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView) { + + class Level1(private val binding: ItemLevel1Binding) : ExpandableViewHolder(binding.root) { + override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + binding.node = node + } + } + + class Level2(private val binding: ItemLevel2Binding) : ExpandableViewHolder(binding.root) { + override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + binding.node = node + binding.isLastItem = isLastItem(node) + } + } + + class Level3(private val binding: ItemLevel3Binding) : ExpandableViewHolder(binding.root) { + override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + binding.node = node + binding.isLastItem = isLastItem(node) + } + } + + abstract fun bind(node: ExpandableTreeNode, nestLevel: Int) + + fun isLastItem(node: ExpandableTreeNode): Boolean { + val parent = node.parent ?: throw IllegalArgumentException("This node hasn't parent") + val childrenSize = parent.children.size + Log.d("DEBUG_TAG", node.value) + return parent.children[childrenSize - 1] == node + } + } + + private fun ViewGroup.inflateLevel1(): ItemLevel1Binding { + return ItemLevel1Binding.inflate(LayoutInflater.from(context), this, false) + } + + private fun ViewGroup.inflateLevel2(): ItemLevel2Binding { + return ItemLevel2Binding.inflate(LayoutInflater.from(context), this, false) + } + + private fun ViewGroup.inflateLevel3(): ItemLevel3Binding { + return ItemLevel3Binding.inflate(LayoutInflater.from(context), this, false) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/adriankuta/MainActivity.kt b/app/src/main/java/com/github/adriankuta/MainActivity.kt index cef3e6c..da606f4 100644 --- a/app/src/main/java/com/github/adriankuta/MainActivity.kt +++ b/app/src/main/java/com/github/adriankuta/MainActivity.kt @@ -1,12 +1,38 @@ package com.github.adriankuta -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.github.adriankuta.expandable_recyclerview.expandableTree +import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + + val tree = expandableTree("World") { + child("North America") { + child("USA") + } + child("Europe") { + child("Poland") { + child("Warsaw") + } + child("Germany") + } + child("Asia") { + child("China") + } + } + + val adapter = ExpandableAdapter() + recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) + recyclerView.adapter = adapter + + adapter.setTree(tree) } } diff --git a/app/src/main/res/drawable/ic_expand_less_black_24dp.xml b/app/src/main/res/drawable/ic_expand_less_black_24dp.xml new file mode 100644 index 0000000..3afdf96 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_less_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_more_black_24dp.xml b/app/src/main/res/drawable/ic_expand_more_black_24dp.xml new file mode 100644 index 0000000..8d57dbc --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_more_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_last_element.xml b/app/src/main/res/drawable/ic_last_element.xml new file mode 100644 index 0000000..6a7e4fa --- /dev/null +++ b/app/src/main/res/drawable/ic_last_element.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_middle_element.xml b/app/src/main/res/drawable/ic_middle_element.xml new file mode 100644 index 0000000..eeab090 --- /dev/null +++ b/app/src/main/res/drawable/ic_middle_element.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_vertical_line.xml b/app/src/main/res/drawable/ic_vertical_line.xml new file mode 100644 index 0000000..b1e6f93 --- /dev/null +++ b/app/src/main/res/drawable/ic_vertical_line.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4fc2444..8a8a45f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,13 +6,13 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - \ No newline at end of file diff --git a/app/src/main/res/layout/item_level_1.xml b/app/src/main/res/layout/item_level_1.xml new file mode 100644 index 0000000..1f76dca --- /dev/null +++ b/app/src/main/res/layout/item_level_1.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_level_2.xml b/app/src/main/res/layout/item_level_2.xml new file mode 100644 index 0000000..2f3c1c6 --- /dev/null +++ b/app/src/main/res/layout/item_level_2.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_level_3.xml b/app/src/main/res/layout/item_level_3.xml new file mode 100644 index 0000000..0a222a0 --- /dev/null +++ b/app/src/main/res/layout/item_level_3.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 12e70f0a6a55fa4c4a47444539bb6c567f0b4c34 Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Tue, 28 Jan 2020 17:31:40 +0100 Subject: [PATCH 2/3] ExpandableRecyclerViewAdapter v1.0.0 --- expandable-recyclerview/build.gradle | 2 +- ...lRecyclerViewAdapter.kt => ExpandableRecyclerViewAdapter.kt} | 2 +- .../adriankuta/expandable_recyclerview/ExpandableTreeNodeExt.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/{MultilevelRecyclerViewAdapter.kt => ExpandableRecyclerViewAdapter.kt} (95%) diff --git a/expandable-recyclerview/build.gradle b/expandable-recyclerview/build.gradle index f38bf75..5cb348b 100644 --- a/expandable-recyclerview/build.gradle +++ b/expandable-recyclerview/build.gradle @@ -15,7 +15,7 @@ android { minSdkVersion 23 targetSdkVersion 29 versionCode 1 - versionName "0.0.1-beta02" + versionName "1.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' diff --git a/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/MultilevelRecyclerViewAdapter.kt b/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableRecyclerViewAdapter.kt similarity index 95% rename from expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/MultilevelRecyclerViewAdapter.kt rename to expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableRecyclerViewAdapter.kt index 0e80119..fd539ba 100644 --- a/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/MultilevelRecyclerViewAdapter.kt +++ b/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableRecyclerViewAdapter.kt @@ -3,7 +3,7 @@ package com.github.adriankuta.expandable_recyclerview import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -abstract class MultilevelRecyclerViewAdapter : +abstract class ExpandableRecyclerViewAdapter : RecyclerView.Adapter() { private lateinit var treeNodes: ExpandableTreeNode diff --git a/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableTreeNodeExt.kt b/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableTreeNodeExt.kt index ec48d7a..535fc7a 100644 --- a/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableTreeNodeExt.kt +++ b/expandable-recyclerview/src/main/java/com/github/adriankuta/expandable_recyclerview/ExpandableTreeNodeExt.kt @@ -6,7 +6,7 @@ import com.github.adriankuta.datastructure.tree.ChildDeclaration @JvmSynthetic inline fun expandableTree( value: T, - childDeclaration: ChildDeclaration + childDeclaration: ChildDeclaration = {} ): ExpandableTreeNode { val treeNode = ExpandableTreeNode(value) treeNode.childDeclaration() From 7494ec14dac327a41e6da5ef3fa9e6cd1398b1fe Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Tue, 28 Jan 2020 17:53:19 +0100 Subject: [PATCH 3/3] Sample with README.md --- README.md | 9 +++-- app/build.gradle | 2 +- .../github/adriankuta/ExpandableAdapter.kt | 39 ++++++++++++------- app/src/main/res/layout/item_level_1.xml | 25 +++++++----- app/src/main/res/layout/item_level_2.xml | 35 +++++++---------- app/src/main/res/layout/item_level_3.xml | 37 ++++-------------- 6 files changed, 67 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 15070e9..0fe570b 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,11 @@ [![License](https://img.shields.io/github/license/AdrianKuta/Expandable-RecyclerView?style=plastic)](https://github.com/AdrianKuta/Expandable-RecyclerView/blob/master/LICENSE) [![CircleCI](https://img.shields.io/circleci/build/github/AdrianKuta/Expandable-RecyclerView/master?label=CircleCI&style=plastic&logo=circleci)](https://circleci.com/gh/AdrianKuta/Expandable-RecyclerView) -Library is currently during implementation! It is **not** ready to use yet :/ + -Final version will be released soon. +This RecyclerViewAdapter use Tree(Data Structure) to keep all objects. +## Download -![Release date](https://img.shields.io/date/1580493319?label=Expected%20release&style=for-the-badge) + implementation "com.github.adriankuta:expandable-recyclerView:$latest_versions" + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 8d17d4f..b09b45e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'com.github.adriankuta:expandable-recyclerView:0.0.1-beta01' + implementation 'com.github.adriankuta:expandable-recyclerView:0.0.1-beta02' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt b/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt index 9cae40c..82f2ff0 100644 --- a/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt +++ b/app/src/main/java/com/github/adriankuta/ExpandableAdapter.kt @@ -1,6 +1,5 @@ package com.github.adriankuta -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -38,39 +37,49 @@ class ExpandableAdapter : treeNode: ExpandableTreeNode, nestLevel: Int ) { - holder.bind(treeNode, nestLevel) + holder.bind(treeNode) { + toggleGroup(it) + } } - sealed class ExpandableViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView) { + sealed class ExpandableViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { class Level1(private val binding: ItemLevel1Binding) : ExpandableViewHolder(binding.root) { - override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + override fun bind( + node: ExpandableTreeNode, + onClickListener: ((ExpandableTreeNode) -> Unit)? + ) { binding.node = node + binding.root.setOnClickListener { onClickListener?.invoke(node) } } } class Level2(private val binding: ItemLevel2Binding) : ExpandableViewHolder(binding.root) { - override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + override fun bind( + node: ExpandableTreeNode, + onClickListener: ((ExpandableTreeNode) -> Unit)? + ) { binding.node = node - binding.isLastItem = isLastItem(node) + binding.root.setOnClickListener { onClickListener?.invoke(node) } } } class Level3(private val binding: ItemLevel3Binding) : ExpandableViewHolder(binding.root) { - override fun bind(node: ExpandableTreeNode, nestLevel: Int) { + override fun bind( + node: ExpandableTreeNode, + onClickListener: ((ExpandableTreeNode) -> Unit)? + ) { binding.node = node - binding.isLastItem = isLastItem(node) + binding.root.setOnClickListener { onClickListener?.invoke(node) } } } - abstract fun bind(node: ExpandableTreeNode, nestLevel: Int) - fun isLastItem(node: ExpandableTreeNode): Boolean { - val parent = node.parent ?: throw IllegalArgumentException("This node hasn't parent") - val childrenSize = parent.children.size - Log.d("DEBUG_TAG", node.value) - return parent.children[childrenSize - 1] == node - } + abstract fun bind( + node: ExpandableTreeNode, + onClickListener: ((ExpandableTreeNode) -> Unit)? = null + ) + } private fun ViewGroup.inflateLevel1(): ItemLevel1Binding { diff --git a/app/src/main/res/layout/item_level_1.xml b/app/src/main/res/layout/item_level_1.xml index 1f76dca..0941bfa 100644 --- a/app/src/main/res/layout/item_level_1.xml +++ b/app/src/main/res/layout/item_level_1.xml @@ -1,38 +1,43 @@ + + - + + + android:layout_height="wrap_content"> + app:layout_constraintTop_toTopOf="@id/textView" + tools:src="@drawable/ic_expand_less_black_24dp" /> + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/full_names" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_level_2.xml b/app/src/main/res/layout/item_level_2.xml index 2f3c1c6..e093466 100644 --- a/app/src/main/res/layout/item_level_2.xml +++ b/app/src/main/res/layout/item_level_2.xml @@ -2,13 +2,11 @@ - - + + - - + android:visibility="@{node.children.empty ? View.GONE : View.VISIBLE}" + app:layout_constraintBottom_toBottomOf="@id/textView" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/textView" + tools:src="@drawable/ic_expand_less_black_24dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_level_3.xml b/app/src/main/res/layout/item_level_3.xml index 0a222a0..cc2e3ae 100644 --- a/app/src/main/res/layout/item_level_3.xml +++ b/app/src/main/res/layout/item_level_3.xml @@ -2,11 +2,6 @@ - - - @@ -20,41 +15,25 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - - -