I created an Android application with a Spinner
and a TextView
. I want to display the selected item from the Spinner's drop down list in the TextView. I implemented the Spinner in the onCreate
method so when I'm running the program, it shows a value in the TextView
(before selecting an item from the drop down list).
I want to show the value in the TextView only after selecting an item from the drop down list. How do I do this?
Here is my code:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
public class GPACal01Activity extends Activity implements OnItemSelectedListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
}
public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
TextView textView = (TextView) findViewById(R.id.textView1);
String str = (String) parent.getItemAtPosition(pos);
textView.setText(str);
}
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
This question is related to
android
android-layout
android-spinner
You can do this by this way:
AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//set the text of TextView
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
yourSpinner.setOnItemSelectedListener(listener);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
At first I create a listener and attributed to a variable callback; then i create a second listener anonymous and when this is called at a first time, this change the listener =]
For me, Abhi's solution works great up to Api level 27.
But it seems that from Api level 28 and upwards, onItemSelected() is not called when listener is set, which means onItemSelected() is never called.
Therefore, I added a short if-statement to check Api level:
public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
if(Build.VERSION.SDK_INT >= 28){ //onItemSelected() doesn't seem to be called when listener is set on Api 28+
check = 1;
}
if(++check > 1) {
//Do your action here
}
}
I think that's quite weird and I'm not sure wether others also have this problem, but in my case it worked well.
This worked for me:
spinner.setSelection(0, false);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
spinner.setOnItemSelectedListener(listener);
}, 500);
Similar simple solution that enables multiple spinners is to put the AdapterView in a collection - in the Activities superclass - on first execution of onItemSelected(...) Then check to see if the AdapterView is in the collection before executing it. This enables one set of methods in the superclass and supports multiple AdapterViews and therefor multiple spinners.
Superclass ...
private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();
protected boolean firstTimeThrough(AdapterView parent) {
boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
if (firstTimeThrough) {
AdapterViewCollection.add(parent);
}
return firstTimeThrough;
}
Subclass ...
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (! firstTimeThrough(parent)) {
String value = safeString(parent.getItemAtPosition(pos).toString());
String extraMessage = EXTRA_MESSAGE;
Intent sharedPreferencesDisplayIntent = new Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
startActivity(sharedPreferencesDisplayIntent);
}
// don't execute the above code if its the first time through
// do to onItemSelected being called during view initialization.
}
Based on Abhi's answer i made this simple listener
class SpinnerListener constructor(private val onItemSelected: (position: Int) -> Unit) : AdapterView.OnItemSelectedListener {
private var selectionCount = 0
override fun onNothingSelected(parent: AdapterView<*>?) {
//no op
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (selectionCount++ > 1) {
onItemSelected(position)
}
}
}
Beginning with API level 3 you can use onUserInteraction() on an Activity with a boolean to determine if the user is interacting with the device.
http://developer.android.com/reference/android/app/Activity.html#onUserInteraction()
@Override
public void onUserInteraction() {
super.onUserInteraction();
userIsInteracting = true;
}
As a field on the Activity I have:
private boolean userIsInteracting;
Finally, my spinner:
mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
spinnerAdapter.setmPreviousSelectedIndex(position);
if (userIsInteracting) {
updateGUI();
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
As you come and go through the activity the boolean is reset to false. Works like a charm.
My solution:
protected boolean inhibit_spinner = true;
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int pos, long arg3) {
if (inhibit_spinner) {
inhibit_spinner = false;
}else {
if (getDataTask != null) getDataTask.cancel(true);
updateData();
}
}
Had the same problem and this works for me:
I have 2 spinners and I update them during init and during interactions with other controls or after getting data from the server.
Here is my template:
public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {
private void removeSpinnersListeners() {
spn1.setOnItemSelectedListener(null);
spn2.setOnItemSelectedListener(null);
}
private void setSpinnersListeners() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
spn1.setOnItemSelectedListener(MyClass.this);
spn2.setOnItemSelectedListener(MyClass.this);
}
}, 1);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Your code here
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
When the class is initiating use setSpinnersListeners() instead of directly setting the listener.
The Runnable will prevent the spinner from firing onItemSelected right after the you set their values.
If you need to update the spinner (after a server call etc.) use removeSpinnersListeners() right before your update lines, and setSpinnersListeners() right after the update lines. This will prevent onItemSelected from firing after the update.
This worked for me
Spinner's initialization in Android is problematic sometimes the above problem was solved by this pattern.
Spinner.setAdapter();
Spinner.setSelected(false); // must
Spinner.setSelection(0,true); //must
Spinner.setonItemSelectedListener(this);
Setting adapter should be first part and onItemSelectedListener(this) will be last when initializing a spinner. By the pattern above my OnItemSelected() is not called during initialization of spinner
Just put this line before set OnItemSelectedListener
spinner.setSelection(0,false)
You could achieve it by setOnTouchListener first then setOnItemSelectedListener in onTouch
@Override
public boolean onTouch(final View view, final MotionEvent event) {
view.setOnItemSelectedListener(this)
return false;
}
To avoid calling spinner.setOnItemSelectedListener() during initialization
spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
create a boolean field
private boolean inispinner;
inside oncreate of the activity
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (!inispinner) {
inispinner = true;
return;
}
//do your work here
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Try this
spinner.postDelayed(new Runnable() {
@Override
public void run() {
addListeners();
}
}, 1000);.o
The user interaction flag can then be set to true in the onTouch method and reset in onItemSelected()
once the selection change has been handled. I prefer this solution because the user interaction flag is handled exclusively for the spinner, and not for other views in the activity that may affect the desired behavior.
In code:
Create your listener for the spinner:
public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {
boolean userSelect = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
userSelect = true;
return false;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (userSelect) {
userSelect = false;
// Your selection handling code here
}
}
}
Add the listener to the spinner as both an OnItemSelectedListener
and an OnTouchListener
:
SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
Code
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override public boolean onTouch(View view, MotionEvent motionEvent) { isSpinnerTouch=true; return false; }});
holder.spinner_from.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int slot_position, long l) {
if(isSpinnerTouch)
{
Log.d("spinner_from", "spinner_from");
spinnerItemClickListener.onSpinnerItemClickListener(position, slot_position, AppConstant.FROM_SLOT_ONCLICK_CODE);
}
else {
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
haha...I have the same question. When initViews() just do like this.The sequence is the key, listener is the last. Good Luck !
spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);
I placed a TextView on top of the Spinner, same size and background as the Spinner, so that I would have more control over what it looked like before the user clicks on it. With the TextView there, I could also use the TextView to flag when the user has started interacting.
My Kotlin code looks something like this:
private var mySpinnerHasBeenTapped = false
private fun initializeMySpinner() {
my_hint_text_view.setOnClickListener {
mySpinnerHasBeenTapped = true //turn flag to true
my_spinner.performClick() //call spinner click
}
//Basic spinner setup stuff
val myList = listOf("Leonardo", "Michelangelo", "Rafael", "Donatello")
val dataAdapter: ArrayAdapter<String> = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, myList)
my_spinner.adapter = dataAdapter
my_spinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
if (mySpinnerHasBeenTapped) { //code below will only run after the user has clicked
my_hint_text_view.visibility = View.GONE //once an item has been selected, hide the textView
//Perform action here
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
//Do nothing
}
}
}
Layout file looks something like this, with the important part being that the Spinner and TextView share the same width, height, and margins:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Spinner
android:id="@+id/my_spinner"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="@drawable/bg_for_spinners"
android:paddingStart="8dp"
android:paddingEnd="30dp"
android:singleLine="true" />
<TextView
android:id="@+id/my_hint_text_view"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="@drawable/bg_for_spinners"
android:paddingStart="8dp"
android:paddingEnd="30dp"
android:singleLine="true"
android:gravity="center_vertical"
android:text="*Select A Turtle"
android:textColor="@color/green_ooze"
android:textSize="16sp" />
</FrameLayout>
I'm sure the other solutions work where you ignore the first onItemSelected call, but I really don't like the idea of assuming it will always be called.
Source: Stackoverflow.com