diff --git a/README.md b/README.md
index d539fa2..65aa43b 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,116 @@
-#
SpinnerTools
-Advanced spinner views for Android including bottomsheets & searching
+#
SpinnerTools [](https://jitpack.io/#MattJAshworth/SpinnerTools)
+Spinner View for Android with bottomsheet and searching built in
+
+# Screenshots
+
+
+# Download
+## build.gradle (Groovy)
+Add to your project level `build.gradle`
+```Java
+allprojects {
+ repositories {
+ ...
+ maven { url "https://jitpack.io" }
+ }
+}
+```
+Add a dependency to your module `build.gradle`:
+```Java
+dependencies {
+ implementation 'com.github.MattJAshworth:SpinnerTools:1.2'
+}
+```
+
+## build.gradle.kts (Kotlin DSL)
+
+Add to `settings.gradle.kts`
+```Kotlin
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven { url = uri("https://www.jitpack.io" ) }
+
+ }
+}
+```
+
+Add a dependency to your `build.gradle.kts`:
+```Kotlin
+dependencies {
+ implementation("com.github.MattJAshworth:SpinnerTools:1.2")
+}
+```
+# Implementation
+Add the `xyz.mattjashworth.spinnertools.sheet.Spinner` to your layout XML file.
+
+Below are all the YesNoButton's xml attributes. You cannot currently set these programmatically.
+```XML
+
+```
+
+When binding to the view element specify the type. For example `ExampleObject`
+```Kotlin
+data class ExampleObject(
+ val name: String,
+ val age: String
+)
+```
+```Kotlin
+val searchSpinner = findViewById>(R.id.app_spinner)
+```
+
+Set the spinner items by calling `setItems()`
+```Kotlin
+searchSpinner.setItems(data)
+```
+
+Attach an item selected listener to return the item selected by the user. The listener returns the type specified. In this case `ExampleObject`.
+```Kotlin
+searchSpinner.setOnItemSelectedListener(object : Spinner.OnItemSelectedListener {
+ override fun onItemSelected(model: ExampleObject) {
+ Snackbar.make(rootView, model.name, Snackbar.LENGTH_LONG).show()
+ }
+
+})
+```
+
+# License
+```
+MIT License
+
+Copyright (c) 2024 Matt J Ashworth
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
\ No newline at end of file
diff --git a/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/Spinner.kt b/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/Spinner.kt
index 9879e5f..80ebc7b 100644
--- a/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/Spinner.kt
+++ b/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/Spinner.kt
@@ -2,40 +2,46 @@ package xyz.mattjashworth.spinnertools.sheet
import android.content.Context
import android.content.res.TypedArray
-import android.graphics.Color
import android.os.Build
import android.util.AttributeSet
+import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
+import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
-import androidx.annotation.AttrRes
+import android.widget.PopupWindow
import androidx.annotation.RequiresApi
import androidx.cardview.widget.CardView
+import androidx.core.content.ContextCompat
+import androidx.core.content.ContextCompat.getSystemService
+import androidx.core.view.marginLeft
+import androidx.core.view.marginRight
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.Gson
import com.google.gson.JsonParser
import xyz.mattjashworth.spinnertools.R
+import xyz.mattjashworth.spinnertools.sheet.adapters.SearchSpinnerAdapter
-
-
-@RequiresApi(Build.VERSION_CODES.N_MR1)
class Spinner(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
private lateinit var selectedItem: EditText
private var card: CardView
private var items = ArrayList()
- private var SelectedObject: T? = null
+ private var selectedObject: T? = null
- private var DisplayMember: String? = null
- private var Title = "Select Item"
- private var SelectedMode: Mode = Mode.Sheet
- private var Searchable = false
- private var DismissWhenSelected = false
+ private var displayMember: String? = null
+ private var title = "Select Item"
+ private var searchable = false
+ private var dismissWhenSelected = false
+
+ private lateinit var textInputLayout: TextInputLayout
- private enum class Mode {Sheet, Dropdown}
private var type: Any? = null
private var onItemSelectedListener: OnItemSelectedListener? = null
@@ -45,25 +51,27 @@ class Spinner(context: Context, attributeSet: AttributeSet) : LinearLayout(co
val root = inflate(context, R.layout.spinner, this)
val ta: TypedArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.Spinner)
- DisplayMember = ta.getString(R.styleable.Spinner_DisplayMember)!!
- SelectedMode = Mode.values()[ta.getInt(R.styleable.Spinner_Mode, 0)]
- Title = ta.getString(R.styleable.Spinner_Title)!!
- Searchable = ta.getBoolean(R.styleable.Spinner_Searchable, false)
- DismissWhenSelected = ta.getBoolean(R.styleable.Spinner_DismissWhenSelected, false)
+ displayMember = ta.getString(R.styleable.Spinner_DisplayMember) ?: ""
+ title = ta.getString(R.styleable.Spinner_Title) ?: ""
+ searchable = ta.getBoolean(R.styleable.Spinner_Searchable, false)
+ dismissWhenSelected = ta.getBoolean(R.styleable.Spinner_DismissWhenSelected, false)
+ ta.recycle()
+
+
selectedItem = findViewById(R.id.tv_spinner_selected)
- val layout = findViewById(R.id.tIL)
+ textInputLayout = findViewById(R.id.tIL)
card = findViewById(R.id.card_spinner)
- layout.hint = Title
+ textInputLayout.hint = title
setChildListener(rootView, OnClickListener {
- val s = SpinnerSheet(context, items, Title, DisplayMember)
- if (SelectedObject != null)
- s.setSelectedObject(SelectedObject!!)
+ val s = SpinnerSheet(context, items, title, displayMember, searchable)
+ if (selectedObject != null)
+ s.setSelectedObject(selectedObject!!)
s.setOnItemClickListener(object : SpinnerSheet.OnSearchSpinnerClickListener {
override fun onClick(position: Int, model: T) {
- if (DismissWhenSelected)
+ if (dismissWhenSelected)
s.dismiss()
val gson = Gson()
@@ -72,6 +80,7 @@ class Spinner(context: Context, attributeSet: AttributeSet) : LinearLayout(co
if (model is String) {
selectedItem.setText(model)
+
} else {
val obj = JsonParser.parseString(jsonStr).asJsonObject
@@ -81,14 +90,16 @@ class Spinner(context: Context, attributeSet: AttributeSet) : LinearLayout(co
var res = ""
- if (!DisplayMember.isNullOrEmpty()) res = obj.get(DisplayMember).asString
+ if (!displayMember.isNullOrEmpty()) res =
+ obj.get(displayMember).asString
else res = obj.get(keys.max()).asString
- SelectedObject = model
+ selectedObject = model
selectedItem.setText(res)
- onItemSelectedListener?.onItemSelected(model)
}
+
+ onItemSelectedListener?.onItemSelected(model)
}
})
@@ -122,11 +133,11 @@ class Spinner(context: Context, attributeSet: AttributeSet) : LinearLayout(co
}
fun setDisplayMember(id: String) {
- DisplayMember = id
+ displayMember = id
}
fun setTitle(title: String) {
- Title = title
+ this.title = title
}
}
\ No newline at end of file
diff --git a/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/SpinnerSheet.kt b/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/SpinnerSheet.kt
index 8e3b1be..9045207 100644
--- a/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/SpinnerSheet.kt
+++ b/SpinnerTools/src/main/java/xyz/mattjashworth/spinnertools/sheet/SpinnerSheet.kt
@@ -2,6 +2,7 @@ package xyz.mattjashworth.spinnertools.sheet
import android.content.Context
import android.view.LayoutInflater
+import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.core.widget.addTextChangedListener
@@ -16,7 +17,7 @@ import xyz.mattjashworth.spinnertools.R
import xyz.mattjashworth.spinnertools.sheet.adapters.SearchSpinnerAdapter
import java.lang.reflect.Modifier
-internal class SpinnerSheet(context: Context, items: ArrayList, title: String, displayMember: String?) {
+internal class SpinnerSheet(context: Context, items: ArrayList, title: String, displayMember: String?, searchable: Boolean) {
private var onSearchSpinnerClickListener: OnSearchSpinnerClickListener? = null
@@ -35,6 +36,7 @@ internal class SpinnerSheet(context: Context, items: ArrayList, title: Str
val spinnerSheetView = layoutInflater.inflate(R.layout.bottomsheet_spinner, null)
val search = spinnerSheetView.findViewById(R.id.et_bottomsheet_search)
+ if (!searchable) search.visibility = View.GONE
val sheetTitle = spinnerSheetView.findViewById(R.id.tv_sheet_title)
sheetTitle.text = title
diff --git a/SpinnerTools/src/main/res/layout/dropdown_spinner.xml b/SpinnerTools/src/main/res/layout/dropdown_spinner.xml
deleted file mode 100644
index 945e480..0000000
--- a/SpinnerTools/src/main/res/layout/dropdown_spinner.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/SpinnerTools/src/main/res/layout/spinner.xml b/SpinnerTools/src/main/res/layout/spinner.xml
index 9024168..c394006 100644
--- a/SpinnerTools/src/main/res/layout/spinner.xml
+++ b/SpinnerTools/src/main/res/layout/spinner.xml
@@ -12,7 +12,6 @@
android:id="@+id/card_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:cardElevation="10dp"
android:background="@android:color/transparent"
app:contentPadding="10dp"
app:cardUseCompatPadding="true"
diff --git a/SpinnerTools/src/main/res/values/attrs.xml b/SpinnerTools/src/main/res/values/attrs.xml
index 48ff5b0..46963f1 100644
--- a/SpinnerTools/src/main/res/values/attrs.xml
+++ b/SpinnerTools/src/main/res/values/attrs.xml
@@ -3,10 +3,6 @@
-
-
-
-
diff --git a/sample/src/main/java/xyz/mattjashworth/sample/MainActivity.kt b/sample/src/main/java/xyz/mattjashworth/sample/MainActivity.kt
index e2829a9..903a372 100644
--- a/sample/src/main/java/xyz/mattjashworth/sample/MainActivity.kt
+++ b/sample/src/main/java/xyz/mattjashworth/sample/MainActivity.kt
@@ -60,9 +60,9 @@ class MainActivity : AppCompatActivity() {
)
- val s = findViewById>(R.id.app_spinner)
- s.setItems(data)
- s.setOnItemSelectedListener(object : Spinner.OnItemSelectedListener {
+ val searchSpinner = findViewById>(R.id.app_spinner)
+ searchSpinner.setItems(data)
+ searchSpinner.setOnItemSelectedListener(object : Spinner.OnItemSelectedListener {
override fun onItemSelected(model: ExampleObject) {
Snackbar.make(rootView, model.name, Snackbar.LENGTH_LONG).show()
}
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
index c9d18f6..359aa4a 100644
--- a/sample/src/main/res/layout/activity_main.xml
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -11,10 +11,13 @@
android:id="@+id/app_spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
- app:DisplayMember="ID"
- app:Mode="Sheet"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="10dp"
+ android:layout_marginEnd="10dp"
app:DismissWhenSelected="true"
- app:Title="Select Remedy Code"
+ app:Title="Select Person"
+ app:Searchable="true"
+ app:DisplayMember="name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/screenshots/spinnertools.gif b/screenshots/spinnertools.gif
new file mode 100644
index 0000000..65e46d4
Binary files /dev/null and b/screenshots/spinnertools.gif differ