Android Spinner is not working, the API is working and the Spinner's list of items is working. However, the item selection is not working.
class PlayerSignup2Activity : AppCompatActivity() {
private lateinit var positions : List<Position>
val positionSpinner = positionsSpinner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(com.example.app.R.layout.activity_user_signup2)
//Positions from API
positions = APIService.getPositions(this)
val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_item, positions)
spinnerAdapter.setDropDownViewResource(R.layout.spinner_item)
positionSpinner.adapter = spinnerAdapter
}
Spinner list
After selecting any item
Any idea on how to fix this?!
Try with this
<Spinner
android:id="#+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
In Kotlin
class MainActivity : /** Other Classes, */AdapterView.OnItemSelectedListener {
var list_of_items = arrayOf("Item 1", "Item 2", "Item 3")
override fun onCreate(savedInstanceState: Bundle?) {
spinner!!.setOnItemSelectedListener(this)
// Create an ArrayAdapter using a simple spinner layout and languages array
val aa = ArrayAdapter(this, android.R.layout.simple_spinner_item, list_of_items)
// Set layout to use when the list of choices appear
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Set Adapter to Spinner
spinner!!.setAdapter(aa)
}
override fun onItemSelected(arg0: AdapterView<*>, arg1: View, position: Int, id:Long{
// use position to know the selected item
//here you will get the answwer
}
override fun onNothingSelected(arg0: AdapterView<*>) {
}
}
try using prompt for adding title in .XML file
<Spinner
android:id="#+id/spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="#string/spinner_title"/>
or try adding 1 more item that contains whatever title you want like "select position" on index 0.
positions.add("select position");
positions.add("value 1");
after adding values to list set spinner value to index 0 by default using below code.
mSpinner.setSelection(0) .
and on Item Selected check if index 0 or value is "select position" then ignore selection else perform action you want.
private lateinit var positions : List<Position>
//add dummy data first
positions.add(Position("select position"));
//Positions from API
positions.addAll(APIService.getPositions(this));
Related
I'm using AndroidStudio 4.1.1 and kotlin
I'm having issues trying to get the value of a selected item in a spinner view/item. My first attempt, and many threads say to do it this way, is:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
val selectedText = spinner.getSelectedItem().toString()
This does not work for me. selectedText shows nothing in a Toast or a println
I also tried this, which I also found many threads for:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
if (spinner != null) {
val adapter = ArrayAdapter( this, android.R.layout.simple_spinner_item, muscleGroups )
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val selectedText = muscleGroups[position]
println("Muscle Group selected is $selectedText") // <-- this works
}
override fun onNothingSelected(parent: AdapterView<*>) {
// write code to perform some action
}
}
}
// selectedText is not seen here:
println("Muscle Group selected is $selectedText")
This works and I can see selectedString in my println, in the onItemSelected function inside the block. But, how do I get this value to be seen outside of this block of code? I need to use this value in a class object and a database write. I've tried declaring selectedString outside/above the if (spinner != null), but that does not seem to work either.
Thanks for any help.
Your Spinner does not have a value selected by default. Hence calling spinner.getSelectedItem() returns null and null.toString() returns an empty String.
Your code will work only if the user has selected an option from the Spinner first. You can set a initial value by using spinner.setSelection(position).
If you want to use the selected value outside the selection, you can use a global variable as follows:
val spinner = findViewById<Spinner>(R.id.wMuscleGroup) as Spinner
var selectedText = muscleGroups.first() // as default
if (spinner != null) {
val adapter = ArrayAdapter( this, android.R.layout.simple_spinner_item, muscleGroups )
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
selectedText = muscleGroups[position]
}
override fun onNothingSelected(parent: AdapterView<*>) {
}
}
}
If you want to try something with selectedText, you should use it inside onItemSelected function.
How do I change the value of a variable using the spinner widget.
strings.xml
<string name="selected_item">Selected item:</string>
<string-array name="Languages">
<item>English</item>
<item>Latin</item>
<item>French</item>
</string-array>
mainactivity
val spinner = findViewById<Spinner>(R.id.spinner)
if (spinner != null) {
val adapter = ArrayAdapter(
this,
android.R.layout.simple_spinner_item, languages
)
spinner.adapter = adapter
spinner.onItemSelectedListener = object :
AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View, position: Int, id: Long
) {
//what to do here?
}
}
}
suppose I want to change the value of this variable
strokeManager.lang = "en"
So you will want to use the position to access it from the list that you used to populate the spinner.
strokeManager.lang = languageMapToLangCode[languages.get(position)]
This should be defined in your class somewhere the spinner can access it
val languageMapToLangCode: HashMap<String, String> = hashMapOf("French" to "fr", "Latin" to "ln", "English to "en")
Long story short. I want my spinner to always show same first item "Add". When item selected from the list it should be gone from the list and the specific action happen. The text "Add" should still appear on spinner. So my question is how to make that spinner always show first item on his dataList? PS. I made that first item in the list don't show when drop down is open.
My layout:
<Spinner
android:id="#+id/spinner_add"
style="#style/Widget.AppCompat.Spinner.Underlined"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="#color/colorButton" />
Method to set spinner adapter with data list:
private fun fillAddSpinner() {
val spinner: Spinner = findViewById(R.id.spinner_add)
val titles: MutableList<String> = ArrayList()
titles.add(resources.getString(R.string.add_advanced_filter))
for (filter in tableAdvancedFilters) {
titles.add(filter.title)
}
val dataAdapter = object : ArrayAdapter<String?>(this, R.layout.spinner_item,
titles as List<String?>
) {
override fun getDropDownView(
position: Int,
convertView: View?,
parent: ViewGroup
): View {
var v: View? = null
// If this is the initial dummy entry, make it hidden
if (position == 0) {
val tv = TextView(context)
tv.height = 0
tv.visibility = View.GONE
v = tv
} else { // Pass convertView as null to prevent reuse of special case views
v = super.getDropDownView(position, null, parent)
}
// Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling
parent.isVerticalScrollBarEnabled = false
return v!!
}
}
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = dataAdapter
}
I want it stay the same like it is now:
After user selects one item from spinner I will render specific filter choices.
If you want to programmatically set spinner selected item use the following: spinnerObject.setSelection(INDEX_OF_ITEM)
I´m trying to display a message when pressing a button but nothing has been selected in list1. And if an item is selected, I want it to get the listView layout visibility set to gone and the website layout visibility set to visible.
All I get when pressing the button is the toast message no matter what.
Here is the code:
My button:
button1.setOnClickListener {
var selectedObj = list1.getSelectedItem()
if (selectedObj == null) {
toast("You need to choose an item form the list first")
}
else {
val builder = AlertDialog.Builder(this)
builder.setTitle("Warning")
builder.setMessage("This service requires data")
builder.setPositiveButton("Yes", { dialogInterface: DialogInterface, i: Int ->
ListView.visibility = View.GONE
website.visibility = View.VISIBLE
})
builder.setNegativeButton("No", { dialogInterface: DialogInterface, i: Int -> })
builder.show()
}
}
here is my listView:
<ListView
android:id="#+id/list1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:choiceMode="singleChoice"
android:focusable="true"
android:focusableInTouchMode="true"
android:listSelector="#android:color/darker_gray"
android:textSize="10dp"
</ListView>
my code:
val nameofanimals = arrayOf("cat","dog","parrot")
val list1 = findViewById(R.id.list1) as ListView
internal lateinit var adapteranimals: ArrayAdapter<String>
my adapter:
adapteranimals = ArrayAdapter(
this#MainActivity,
R.layout.list1layout,
nameofanimals)
list1.adapter = adapteranimals
Tyvm in advance for yout support
Regards.
ListView does not store selectedItem position when you set choice mode. It stores the checked item position.
Check this out
class MainActivity : AppCompatActivity() {
private lateinit var listView:ListView
internal lateinit var adapteranimals: ArrayAdapter<String>
val nameofanimals = arrayOf("cat","dog","parrot")
private lateinit var btn1:Button
private lateinit var myobject:String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listView = findViewById<ListView>(R.id.list1)
btn1 = findViewById<Button>(R.id.btn1)
adapteranimals = ArrayAdapter(
this#MainActivity,
R.layout.list1layout,
nameofanimals)
listView.adapter = adapteranimals
btn1.setOnClickListener {
val pos = listView.getCheckedItemPosition()
myobject = listView.getAdapter().getItem(pos) as String
Log.d("Selected item",myobject);
}
}
}
You are trying to access the variable from list and you expect the list to store that variable position. But unfortunately list does not save the click item position. Use this code and the item that is clicked is in position.
ListView list = (ListView) findViewById(R.id.listview);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Object listItem = list.getItemAtPosition(position);
ListView.visibility = View.GONE
website.visibility = View.VISIBLE
//you can get the list item clicked in position variable
}
});
I know there have been several questions that dealt with the problem how to add the "Select one..." hint for the Spinner before the first selection is made. But that's not my case.
What I need is to display the hint only when the SpinnerAdapter is empty. By default in such case, nothing happens on click (but that is not the major problem), and most of all, the spinner doesn't display any text, so it looks like this, which obviously doesn't feel right:
Any idea how to simply handle this problem? I've come up with 2 possible solutions, but I don't like any of them very much:
If the SpinnerAdapter is empty, hide the Spinner from the layout and display a TextView with the same background as the Spinner instead.
Implement a custom SpinnerAdapter whose getCount() returns 1 instead of 0 if the internal list is empty, and at the same time, have its getView() return a TextView with the required "Empty" message, possibly grey-coloured. But that would require specific checking if the selected item is not the "Empty" one.
You can use this SpinnerWithHintAdapter class below
class SpinnerWithHintAdapter(context: Context, resource: Int = android.R.layout.simple_spinner_dropdown_item) :
ArrayAdapter<Any>(context, resource) {
override fun isEnabled(position: Int): Boolean {
return position != 0
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
return (super.getDropDownView(position, convertView, parent) as TextView).apply {
if (position == 0) {
// Set the hint text color gray
setTextColor(Color.GRAY)
} else {
setTextColor(Color.BLACK)
}
}
}
fun attachTo(spinner: Spinner, itemSelectedCallback: ((Any?) -> Unit)? = null) {
spinner.apply {
adapter = this#SpinnerWithHintAdapter
itemSelectedCallback?.let {
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedItem = parent?.getItemAtPosition(position)
// If user change the default selection
// First item is disable and it is used for hint
if (position > 0) {
it(selectedItem)
}
}
}
}
}
}
}
How to use? Let's assume I have data class called City
data class City(
val id: Int,
val cityName: String,
val provinceId: Int
) {
/**
* By overriding toString function, you will show the dropdown text correctly
*/
override fun toString(): String {
return cityName
}
}
In the activity, initiate the adapter, add hint(first item), add main items, and finally attach it to your spinner.
SpinnerWithHintAdapter(this#MyActivity)
.apply {
// add hint
add("City")
// add your main items
for (city in cityList) add(city)
// attach this adapter to your spinner
attachTo(yourSpinner) { selectedItem -> // optional item selected listener
selectedItem?.apply {
if (selectedItem is City) {
// do what you want with the selected item
}
}
}
}