I am using kotlin and android 8.0, I have 2 spinners in my code, 1 of them was created using a string array from resource and another was created with an ArrayList. For the spinner that was created with an ArrayList, when clicking on the item, it does not run the OnItemSelected function and does not update the spinner.
Here is my kotlin code for the spinner
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
println(moduleCodeArray)
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
ArrayAdapter(
this,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
}
EDIT: I have fixed the problem! In the code I provided, you can see my ArrayList being filled in an onItemSelected function, for some reason, the ArrayAdapter has to be in that function as well, so the correct code should look something like this.
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
ArrayAdapter(
applicationContext,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
Your Code Seems correct , I have used the same code provided by you and it worked correctly.
May you have error in custom_spinner or custom_spinner_dropdown !![You can share these layouts ]
This is what I have done:
spinner example
Related
I can't seem to get my driver to update through my app. I have tried but with no luck. I have a possible solution but don't know what the adapter is that needs to be used. This data all happens in my MainActivity. When the new spinner item is selected. I pass the driver through to do new calculations with the correct DRIVER data.
My spinner class:
private fun Spinner( tripsheetlist: ArrayList<DataModel>): String {
var driverlist = tripsheetlist.distinctBy { it.DRIVER }
var driver : String = driverlist[1].DRIVER //this will be the default first picked driver
spnDriver.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
driver = driverlist[p2].DRIVER.toString()
Toast.makeText(this#MainActivity, "Driver $driver selected", Toast.LENGTH_SHORT).show()
myAdapter.notifyItemChanged(p2);
// myAdapter.notifyDataSetChanged()
}
override fun onNothingSelected(p0: AdapterView<*>?) {
}
}
return driver
}
Calling class:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerViewTripsheetlist.layoutManager = LinearLayoutManager(this)
val spnDriver: Spinner = findViewById(R.id.spnDriver)
var adapter = ArrayAdapter<String>(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
conn(adapter, spnDriver)
}
private fun conn(adapter: ArrayAdapter<String>, spnDriver: Spinner) {
var tripsheetlist = ArrayList<DataModel>()
//populated by sql - removed for clarity
populatespinner(tripsheetlist, adapter)
var driver : String = Spinner(tripsheetlist)
var driverList : ArrayList<DataModel> = datafilter(tripsheetlist, driver)
tripsheetlist = driverList
weightsum(tvTotalweight, tripsheetlist)
totaldelNotes(tvTotaldelv,tripsheetlist)
runOnUiThread {
recyclerViewTripsheetlist.adapter = TableViewAdapter(tripsheetlist, driver, tvHeader, adapter)
}
}
Thank you for all and any help.
I want to populate spinner with room database in kotlin but items in spinner are different. the number of items are true. exactly I want to make ArrayList of title in Category Class and show them in spinner in a fragment
#Entity(tableName = "cat_table")
class Category(val title: String,
val fulType: Int,
val SaleP: Long,
val BuyP: Long,
var created: Date = Date()
) {
#PrimaryKey(autoGenerate = true)
var id: Int = 0
}`
by this an want to show all title in ArrayList and set to spinner
private fun initData() {
val packageTypesAdapter = context?.let {ArrayAdapter<Any>(it,android.R.layout.simple_spinner_item)}
catViewModel!!.allCats.observe(viewLifecycleOwner, Observer { packageTypes ->
packageTypes?.forEach {packageTypesAdapter!!.add(it)}
})
spinner2.adapter = packageTypesAdapter
spinner2.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
Toast.makeText(context, "$packageTypesAdapter", Toast.LENGTH_SHORT).show()
//if (i == 0) {
// loadAllTodos()
//} else {
// val string: String = parent.getItemAtPosition(position).toString()
// loadFilteredTodos(string)
//}
}
override fun onNothingSelected(adapterView: AdapterView<*>) {
}
}
}`
if use this query
#get:Query("SELECT * FROM cat_table WHERE title ")
val allCatTitle: LiveData<List<Category>>
spinner nothing to show and below query are like this picture
#get:Query("SELECT * FROM cat_table ORDER BY created DESC")
val allCatByDate: LiveData<List<Category>>
Please check the photo
In case someone else bumps into the same issue. Here's how I did it a while ago (Kotlin).
Dao
#Query("SELECT deviceName FROM device_table WHERE deviceType = :deviceType")
fun getDevice(deviceType: String): LiveData<List<String>>
Repository
fun getDevice(deviceType: String): LiveData<List<String>> {
return deviceDao.getDevice(deviceType)
}
ViewModel
fun getDevice(deviceType: String): LiveData<List<String>> {
return repository.getDevice(deviceType)
}
And finally in my fragment:
private fun initSpinnerData() {
val spinner3 = view?.findViewById<Spinner>(R.id.spinnerRecord_devices)
if (spinner3 != null) {
val allDevices = context?.let {
ArrayAdapter<Any>(it, R.layout.spinner_text)
}
mDevicesViewModel.getDevice("Appliance")
.observe(viewLifecycleOwner, { devices ->
devices?.forEach {
allDevices?.add(it)
}
})
spinner3.adapter = allDevices
spinner3.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
Toast.makeText(requireContext(), "$allDevices", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
}
}
I have a view Model which has a field district which is the type of MutableLiveData<String> I have initialized it with var district = MutableLiveData<String>("") I want to bind the selected item to it for that i have a BindingClass
object SpinnerBindingUtil {
#BindingAdapter(value = ["selectedValue", "selectedValueAttrChanged"], requireAll = false)
fun bindSpinnerData(
pAppCompatSpinner: Spinner,
newSelectedValue: String,
newTextAttrChanged: InverseBindingListener
) {
pAppCompatSpinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View,
position: Int,
id: Long
) {
newTextAttrChanged.onChange()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
if (newSelectedValue != null) {
val pos =
(pAppCompatSpinner.adapter as ArrayAdapter<String?>).getPosition(
newSelectedValue
)
pAppCompatSpinner.setSelection(pos, true)
}
}
#InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
fun captureSelectedValue(pAppCompatSpinner: AppCompatSpinner): String {
return pAppCompatSpinner.selectedItem as String
}
}
and here is my xml
<Spinner
selectedValue="#=
{addConsumerViewModel.district}"
android:entries="#array/districts"
android:id="#+id/districtSpinner"
style="#style/AddConsumerSpinner"/>
but i am getting error how can i solve this
In kotlin you have to use kapt to working with data binding properly. In your module level build.gradle apply this plugin.
apply plugin: 'kotlin-kapt'
After that you probably face error: expected type issues. Then make your binding adapter like simple kt file by removing object SpinnerBindingUtil {}:
#BindingAdapter(value = ["selectedValue", "selectedValueAttrChanged"], requireAll = false)
fun bindSpinnerData(
pAppCompatSpinner: Spinner,
newSelectedValue: String,
newTextAttrChanged: InverseBindingListener
) {
pAppCompatSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View,
position: Int,
id: Long
) {
newTextAttrChanged.onChange()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
if (newSelectedValue != null) {
val pos =
(pAppCompatSpinner.adapter as ArrayAdapter<String?>).getPosition(
newSelectedValue
)
pAppCompatSpinner.setSelection(pos, true)
}
}
#InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
fun captureSelectedValue(pAppCompatSpinner: AppCompatSpinner): String {
return pAppCompatSpinner.selectedItem as String
}
I've implemented an ArrayAdapter to populate my Spinner view. The Spinner is working fine, however android is not detecting when I click an item in the spinner.
I've abided by all the requirements in the spinner example in the Android docs
including implementing AdapterView.OnItemSelectedListener to my Activity and overriding it's two methods OnItemSelectedListener and onNothingSelected, however, none of my Log statements in those methods print so they are not being called.
I've also set the listener to my spinner via choose_user.onItemSelectedListener = this#PlayerDetails.
Here's my activity:
class PlayerDetails : AppCompatActivity(), View.OnClickListener, TextWatcher, AdapterView.OnItemSelectedListener {
val TAG: String = "PlayerDetails"
val FirebaseTAG: String = "FirebaseDebug"
var numOfPlayers: Int = 1
var currentPlayer: Int = 1
var name: String = ""
var age: Int = 0
var genderId: Int = 0
var genderResult: String = ""
val db = FirebaseFirestore.getInstance()
var users: MutableList<String> = mutableListOf()
private lateinit var binding: ActivityPlayerDetailsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val sharedPref = this#PlayerDetails.getPreferences(Context.MODE_PRIVATE)
val applicationID: String? = sharedPref.getString("applicationID", null)
binding = DataBindingUtil.setContentView(this, R.layout.activity_player_details)
if (applicationID != null) {
db.collection("phones").document(applicationID)
.collection("users")
.get()
.addOnSuccessListener { result ->
for (document in result){
val name = document.get("name").toString()
users.add(name)
}
}
Log.d(FirebaseTAG, users.toString())
val spinnerAdaptor = ArrayAdapter<String>(this#PlayerDetails, android.R.layout.simple_spinner_item, users)
spinnerAdaptor.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
choose_user?.adapter = spinnerAdaptor
choose_user.onItemSelectedListener = this#PlayerDetails
}
val intent = getIntent()
numOfPlayers = intent.getIntExtra("number_of_players", 1)
next_details.setOnClickListener(this)
player_name.addTextChangedListener(this)
player_age.addTextChangedListener(this)
gender.setOnCheckedChangeListener(object: RadioGroup.OnCheckedChangeListener {
override fun onCheckedChanged(radiogroup: RadioGroup, checked: Int) {
if (fieldsArePopulated()) next_details.visibility = View.VISIBLE
}
})
}
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenName: String = parent?.getItemAtPosition(position).toString()
Log.d("ChosenName", chosenName)
Log.d("adapterclicked", "adapterclicked")
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Log.d("Nothing", "NOTHINGCALLED")
}
...
Any idea what the problem is?
Also, when I select an item in the Spinner the view next to my spinner moves, so it's obviously being detected but onItemSelected() is still not being called.
I set an initial value to the users MutableList:
var users: MutableList<String> = mutableListOf("Choose User")
and now onItemSelected() is successfully being called.
I'm pretty sure onItemSelected returns an int of the item's position in array. So you have to save that as an int instead of string, and then add another variable that us a string and array[intSaved]
Edit
var chosenName = choose_user.onItemSelected("name")
try this
before :
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenName: String = parent?.getItemAtPosition(position).toString()
Log.d("ChosenName", chosenName)
Log.d("adapterclicked", "adapterclicked")
}
after :
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenNameTextView = parent!!.getChildAt(0) as TextView
Log.e("MainActivity","choose Spin : ${chosenNameTextView.text.toString()}")
}
I have in one activity 6 spinners and at the beginnig to 1st one it fetchs data automatically using rest api and retrofit and the for another spinner i need use value which was selected from 1st spinner and fo the 3d spinner i need get selectedItem from second spinner and so on.
i've allready (for fast result) try this in my Activity class:
private fun buildCountryDropDown(order: Int, objectName: Spinner?) {
try {
var rooms: Call<Created>? = null
var selectedObject: String? = null
val data = jsonApi.getObjects()
data?.enqueue(object : Callback<Created> {
override fun onResponse(call: Call<Created>, response: Response<Created>) {
if (response.isSuccessful) {
listOfDataObjects = response.body()!!.data.toMutableList()
println("text==========: " + response.body()?.data?.get(0)?.NameRu)
val cAdapter = CreatedAdapter(this#PlanJobActivity, android.R.layout.simple_spinner_item, listOfDataObjects as ArrayList<Data>?)
objectName?.adapter = cAdapter
}
}
override fun onFailure(call: Call<Created>?, t: Throwable?) {
t?.printStackTrace()
}
})
objectName?.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
selectedObject = listOfDataObjects[position].tid
rooms = jsonApi.getRooms(selectedObject!!)
showToast("$selectedObject was selected!")
}
override fun onNothingSelected(parent: AdapterView<*>) {}
}
//=============================================ROOMS============================
rooms?.enqueue(object : Callback<Created> {
override fun onResponse(call: Call<Created>, response: Response<Created>) {
if (response.isSuccessful) {
listOfRooms = response.body()!!.data.toMutableList()
println("text==========: " + response.body()?.data?.get(0)?.NameRu)
val cAdapter = CreatedAdapter(this#PlanJobActivity, android.R.layout.simple_spinner_item, listOfRooms as ArrayList<Data>?)
vnp?.adapter = cAdapter
}
}
override fun onFailure(call: Call<Created>?, t: Throwable?) {
t?.printStackTrace()
}
})
vnp?.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
selectedObject = listOfRooms[position].tid
showToast("$selectedObject was selected!")
}
override fun onNothingSelected(parent: AdapterView<*>) {}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
I know it is very very bad idea to write logic in activity but i just try, but not works. it fetch data only for first spinner but other spinners stay empty. For fetching data from rest api i'm using a retrofit and how can you see i get data from responce by enqueue method witch allows me to fetch data async. I understand that i need remaster my project to MVP but i dont know how to start?