Skip to content

Commit e3cc80c

Browse files
committed
Add search view
1 parent 3327b03 commit e3cc80c

File tree

5 files changed

+145
-15
lines changed

5 files changed

+145
-15
lines changed

app/src/main/java/com/minibugdev/sheetselection/demo/MainActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class MainActivity : AppCompatActivity() {
2525
.items(items)
2626
.selectedPosition(2)
2727
.showDraggedIndicator(true)
28+
.searchEnabled(true)
2829
.onItemClickListener { item, position ->
2930
textview.text = "You selected `${item.value}`, At position [$position]."
3031
}
@@ -46,6 +47,7 @@ class MainActivity : AppCompatActivity() {
4647
)
4748
.selectedPosition(2)
4849
.showDraggedIndicator(true)
50+
.searchEnabled(true)
4951
.theme(R.style.Theme_Custom_SheetSelection)
5052
.onItemClickListener { item, position ->
5153
textview.text = "You selected `${item.value}`, At position [$position]."

sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelection.kt

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,37 @@ import android.view.LayoutInflater
66
import android.view.View
77
import android.view.ViewGroup
88
import androidx.annotation.StyleRes
9+
import androidx.appcompat.widget.SearchView
910
import androidx.fragment.app.Fragment
1011
import androidx.fragment.app.FragmentActivity
1112
import androidx.fragment.app.FragmentManager
13+
import com.google.android.material.bottomsheet.BottomSheetBehavior
14+
import com.google.android.material.bottomsheet.BottomSheetDialog
1215
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
1316
import kotlinx.android.synthetic.main.dialog_sheet_selection.*
1417

1518
class SheetSelection private constructor() : BottomSheetDialogFragment() {
1619

1720
var onItemClickListener: OnItemSelectedListener? = null
1821

22+
private val adapter by lazy {
23+
SheetSelectionAdapter(
24+
source = arguments?.getParcelableArrayList(ARGS_ITEMS) ?: emptyList(),
25+
selectedPosition = arguments?.getInt(ARGS_SELECTED_POSITION, NO_SELECT) ?: NO_SELECT,
26+
onItemSelectedListener = onItemSelectedListener
27+
)
28+
}
29+
30+
private val screenHeight by lazy {
31+
val statusBarHeight = try {
32+
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
33+
resources.getDimensionPixelSize(resourceId)
34+
} catch (e: Exception) {
35+
0
36+
}
37+
resources.displayMetrics.heightPixels - statusBarHeight
38+
}
39+
1940
override fun getTheme(): Int = arguments?.getInt(ARGS_THEME) ?: super.getTheme()
2041

2142
override fun onCreateView(
@@ -36,23 +57,61 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() {
3657
val title = args.getString(ARGS_TITLE)
3758
if (title.isNullOrEmpty()) {
3859
textViewTitle.visibility = View.GONE
60+
textViewTitle.text = null
3961
} else {
62+
textViewTitle.visibility = View.VISIBLE
4063
textViewTitle.text = title
4164
}
4265

43-
recyclerViewSelectionItems.adapter = SheetSelectionAdapter(
44-
items = args.getParcelableArrayList(ARGS_ITEMS) ?: emptyList(),
45-
selectedPosition = args.getInt(ARGS_SELECTED_POSITION, NO_SELECT),
46-
onItemSelectedListener = internalOnItemSelectedListener
47-
)
66+
if (args.getBoolean(ARGS_SEARCH_ENABLED)) {
67+
buttonSearch.visibility = View.VISIBLE
68+
buttonSearch.setOnClickListener(onSearchClickListener)
69+
searchView.setOnCloseListener(onSearchCloseListener)
70+
searchView.setOnQueryTextListener(onSearchQueryTextListener)
71+
}
72+
73+
recyclerViewSelectionItems.setHasFixedSize(true)
74+
recyclerViewSelectionItems.adapter = adapter
4875
}
4976
}
5077

51-
private val internalOnItemSelectedListener: OnItemSelectedListener = { item, position ->
78+
private fun updateSheetHeight(viewHeight: Int) {
79+
rootLayout.layoutParams = rootLayout.layoutParams
80+
.apply { height = viewHeight }
81+
}
82+
83+
private val onItemSelectedListener: OnItemSelectedListener = { item, position ->
5284
dismiss()
5385
onItemClickListener?.invoke(item, position)
5486
}
5587

88+
private val onSearchClickListener = View.OnClickListener {
89+
(dialog as? BottomSheetDialog)?.run {
90+
behavior.state = BottomSheetBehavior.STATE_EXPANDED
91+
}
92+
updateSheetHeight(screenHeight)
93+
viewSwitcherHeader.displayedChild = 1
94+
searchView.isIconified = false
95+
}
96+
97+
private val onSearchCloseListener = SearchView.OnCloseListener {
98+
updateSheetHeight(ViewGroup.LayoutParams.WRAP_CONTENT)
99+
viewSwitcherHeader.displayedChild = 0
100+
true
101+
}
102+
103+
private val onSearchQueryTextListener = object : SearchView.OnQueryTextListener {
104+
override fun onQueryTextChange(newText: String?): Boolean {
105+
adapter.search(newText)
106+
return true
107+
}
108+
109+
override fun onQueryTextSubmit(query: String?): Boolean {
110+
adapter.search(query)
111+
return true
112+
}
113+
}
114+
56115
class Builder(context: Context) {
57116
private val manager: FragmentManager? = when (context) {
58117
is FragmentActivity -> context.supportFragmentManager
@@ -66,6 +125,7 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() {
66125
private var items: List<SheetSelectionItem> = emptyList()
67126
private var selectedPosition: Int = NO_SELECT
68127
private var showDraggedIndicator: Boolean = false
128+
private var searchEnabled: Boolean = false
69129
private var listener: OnItemSelectedListener? = null
70130

71131
fun theme(@StyleRes themeId: Int) = apply {
@@ -93,6 +153,10 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() {
93153
this.showDraggedIndicator = show
94154
}
95155

156+
fun searchEnabled(enabled: Boolean) = apply {
157+
this.searchEnabled = enabled
158+
}
159+
96160
fun onItemClickListener(listener: OnItemSelectedListener) = apply {
97161
this.listener = listener
98162
}
@@ -105,6 +169,7 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() {
105169
putParcelableArrayList(ARGS_ITEMS, ArrayList(items))
106170
putInt(ARGS_SELECTED_POSITION, selectedPosition)
107171
putBoolean(ARGS_SHOW_DRAGGED_INDICATOR, showDraggedIndicator)
172+
putBoolean(ARGS_SEARCH_ENABLED, searchEnabled)
108173
}
109174
onItemClickListener = listener
110175
}
@@ -124,5 +189,6 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() {
124189
private const val ARGS_ITEMS = "SheetSelection:ARGS_ITEMS"
125190
private const val ARGS_SELECTED_POSITION = "SheetSelection:ARGS_SELECTED_POSITION"
126191
private const val ARGS_SHOW_DRAGGED_INDICATOR = "SheetSelection:ARGS_SHOW_DRAGGED_INDICATOR"
192+
private const val ARGS_SEARCH_ENABLED = "SheetSelection:ARGS_SEARCH_ENABLED"
127193
}
128194
}

sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionAdapter.kt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import kotlinx.android.synthetic.main.row_selection_item.*
1010
typealias OnItemSelectedListener = (item: SheetSelectionItem, position: Int) -> Unit
1111

1212
class SheetSelectionAdapter(
13-
private val items: List<SheetSelectionItem>,
13+
private val source: List<SheetSelectionItem>,
1414
private val selectedPosition: Int,
1515
private val onItemSelectedListener: OnItemSelectedListener?
1616
) : RecyclerView.Adapter<SheetSelectionAdapter.ViewHolder>() {
1717

18+
private var items: List<SheetSelectionItem> = source
19+
1820
override fun getItemCount() = items.size
1921

2022
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -27,13 +29,31 @@ class SheetSelectionAdapter(
2729

2830
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
2931
holder.onBindView(
30-
items[position],
31-
position,
32-
position == selectedPosition,
33-
onItemSelectedListener
32+
item = items[position],
33+
position = position,
34+
selected = position == selectedPosition,
35+
onItemSelectedListener = onItemSelectedListener
3436
)
3537
}
3638

39+
fun search(keyword: String?) {
40+
if (keyword.isNullOrBlank()) {
41+
updateItems(source)
42+
} else {
43+
val searchResult = source.filter { it.value.contains(keyword, true) }
44+
if (searchResult.isEmpty()) {
45+
updateItems(listOf(SheetSelectionItem("search_not_found", "Search not found.")))
46+
} else {
47+
updateItems(searchResult)
48+
}
49+
}
50+
}
51+
52+
private fun updateItems(items: List<SheetSelectionItem>) {
53+
this.items = items
54+
notifyDataSetChanged()
55+
}
56+
3757
class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
3858
LayoutContainer {
3959

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24.0"
5+
android:viewportHeight="24.0">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
9+
</vector>

sheetselection/src/main/res/layout/dialog_sheet_selection.xml

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
xmlns:tools="http://schemas.android.com/tools"
5+
android:id="@+id/rootLayout"
56
android:layout_width="match_parent"
67
android:layout_height="wrap_content"
78
android:orientation="vertical"
@@ -15,12 +16,44 @@
1516
android:visibility="gone"
1617
tools:visibility="visible" />
1718

18-
<TextView
19-
android:id="@+id/textViewTitle"
20-
style="?attr/sheetSelection_titleStyle"
19+
<ViewSwitcher
20+
android:id="@+id/viewSwitcherHeader"
2121
android:layout_width="match_parent"
2222
android:layout_height="wrap_content"
23-
tools:text="@tools:sample/lorem" />
23+
android:measureAllChildren="false">
24+
25+
<LinearLayout
26+
android:layout_width="match_parent"
27+
android:layout_height="wrap_content"
28+
android:orientation="horizontal">
29+
30+
<TextView
31+
android:id="@+id/textViewTitle"
32+
style="?attr/sheetSelection_titleStyle"
33+
android:layout_width="0dp"
34+
android:layout_height="wrap_content"
35+
android:layout_weight="1"
36+
tools:text="@tools:sample/lorem" />
37+
38+
<androidx.appcompat.widget.AppCompatImageButton
39+
android:id="@+id/buttonSearch"
40+
android:layout_width="wrap_content"
41+
android:layout_height="wrap_content"
42+
android:layout_gravity="center_vertical"
43+
android:layout_marginEnd="8dp"
44+
android:src="@drawable/ic_search"
45+
android:visibility="gone"
46+
app:backgroundTint="?attr/colorSurface"
47+
tools:visibility="visible" />
48+
</LinearLayout>
49+
50+
<androidx.appcompat.widget.SearchView
51+
android:id="@+id/searchView"
52+
android:layout_width="match_parent"
53+
android:layout_height="wrap_content"
54+
app:queryBackground="@null"
55+
app:submitBackground="@null" />
56+
</ViewSwitcher>
2457

2558
<androidx.recyclerview.widget.RecyclerView
2659
android:id="@+id/recyclerViewSelectionItems"

0 commit comments

Comments
 (0)