I have a spinner in my android app which is used to call an api to change the data in list view bellow it. I have used OnItemSelectedListener for this, but when I click the same item again, nothing happens, unless I change it to some other item and again click on the item I needed. I want to use something similar to OnItemClick, as OnItemClick is not supported by spinner. Suggest me an alternative, please.
Took from this answer. Unfortunately, android Spinner doesn't provide functionality, that you want, but you can extend it and handle clicks manually:
public class NDSpinner extends Spinner {
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void
setSelection(int position, boolean animate) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
#Override
public void setSelection ( int position){
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
}
Related
I want to turn off getting onItemSelectedListener when I do
spinInsuranceList.setSelection(previousSpinnerPos);
I already made custom class, but now I want to override onItemSelected and make same method with my own extra parameter which help me to stop fire event.
Please Note: I already implemented spinner and it is working fine, so because of onItemSelected custom impl, my exisiting work should not effect.
Code:
CustomSpinnerClass: (I made this custom class, because that time I wanted to click on same item which is selected previously)
import android.content.Context;
import android.util.AttributeSet;
public class CustomSpinnerClass extends androidx.appcompat.widget.AppCompatSpinner {
public CustomSpinnerClass(Context context) {
super(context);
}
public CustomSpinnerClass(Context context, int mode) {
super(context, mode);
}
public CustomSpinnerClass(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void setSelection(int position, boolean animate) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
//TODO:-> Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override
public void setSelection(int position) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
//TODO:-> Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
I found this solution, but don't know how to use:
private Spinner.OnItemSelectedListener spinnerListener
= new Spinner.OnItemSelectedListener(){
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
/* This function is called when you select something from the spinner */
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
/**This line sets the index of the spinner.
Here I have given it as position which
can be any number with in the index range ***/
my_spinner.setSelection(position);
}};
Please read, if you don't understood my requirement: https://forums.xamarin.com/discussion/6350/help-stopping-spinner-itemselected-from-firing-on-setselection
When I want to set something without firing the listener what I do is
spinner.setSelectionListener(null);
spinner.setSelection(20);
spinner.setSelectionListener(this);
In my application I am creating spinner dynamically in code.I want to force user to click on Spinner and change its value/content. Otherwise user should not be able to go to next screen by clicking Next button.
How to do that in Android? Anybody has any idea?
Thanks in Advance.
Rohan
you can use this:
if (spin.getSelectedItemPosition() < 0) {//Do something}
this means user hasn't selected anything.
Let the Spinner's first value be something like "-please select-".
when the user clicks on the next button perform validation and check whether the value of the selectedItem in the spinner is "-please select-" and if yes, then display a toast and ask the the user to select something from the spinner.
you need code, let me know.
Use this code for checking the spinner item is selected or not.
both flags take at class level (Globally).
Boolean temp = false;
Boolean check = false;
spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
if(temp){
check = true;
}
temp = true;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
check = false;
}
});
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(check){
//perform when user select spinner item
}else{
//put Dialog for alert please select spinner item
}
}
}
Call your Intent for the next Activity in the Click Listener of that spinner
Create one boolean global variable like..
boolean isSelect = false;
Now when user select value from spinner then make it isSelect = false. And when user click on NEXT button check condition for isSelect is true or false.
That's it.
You can get the selected item value by using the following method.
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
if (spinner.getSelectedItem().toString().equals("YourValue")) {
Intent yourIntent = new Intent(this,YourClassName.class);
startActivity(yourIntent);
}
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
In my case I added an extra item on first position of the list
1."Select Something"
2."Go next"
3."Go Previous"
5....
6..
then in use
String item=spinnerObject.getSelectedItem ();
now check if("Select Something".equels(item)){
show some dialog to select anything from spinner
}else{
send it to next screen
}
I made a new Spinner class encapsulating the above mentioned principles. But even then you have to make sure to call the correct method and not setSelection
Same thing in a gist
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
/**
* Used this to differentiate between user selected and prorammatically selected
* Call {#link Spinner#programmaticallySetPosition} to use this feature.
* Created by vedant on 6/1/15.
*/
public class Spinner extends android.widget.Spinner implements AdapterView.OnItemSelectedListener {
OnItemSelectedListener mListener;
/**
* used to ascertain whether the user selected an item on spinner (and not programmatically)
*/
private boolean mUserActionOnSpinner = true;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mListener != null) {
mListener.onItemSelected(parent, view, position, id, mUserActionOnSpinner);
}
// reset variable, so that it will always be true unless tampered with
mUserActionOnSpinner = true;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if (mListener != null)
mListener.onNothingSelected(parent);
}
public interface OnItemSelectedListener {
/**
* <p>Callback method to be invoked when an item in this view has been
* selected. This callback is invoked only when the newly selected
* position is different from the previously selected position or if
* there was no selected item.</p>
*
* Impelmenters can call getItemAtPosition(position) if they need to access the
* data associated with the selected item.
*
* #param parent The AdapterView where the selection happened
* #param view The view within the AdapterView that was clicked
* #param position The position of the view in the adapter
* #param id The row id of the item that is selected
*/
void onItemSelected(AdapterView<?> parent, View view, int position, long id, boolean userSelected);
/**
* Callback method to be invoked when the selection disappears from this
* view. The selection can disappear for instance when touch is activated
* or when the adapter becomes empty.
*
* #param parent The AdapterView that now contains no selected item.
*/
void onNothingSelected(AdapterView<?> parent);
}
public void programmaticallySetPosition(int pos, boolean animate) {
mUserActionOnSpinner = false;
setSelection(pos, animate);
}
public void setOnItemSelectedListener (OnItemSelectedListener listener) {
mListener = listener;
}
public Spinner(Context context) {
super(context);
super.setOnItemSelectedListener(this);
}
public Spinner(Context context, int mode) {
super(context, mode);
super.setOnItemSelectedListener(this);
}
public Spinner(Context context, AttributeSet attrs) {
super(context, attrs);
super.setOnItemSelectedListener(this);
}
public Spinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
super.setOnItemSelectedListener(this);
}
public Spinner(Context context, AttributeSet attrs, int defStyle, int mode) {
super(context, attrs, defStyle, mode);
super.setOnItemSelectedListener(this);
}
}
I'm using spinner controls in an Android application, and I handle user selections via an onItemSelectedListener() method. This seems to work okay when a different selection from the current one is made. I would like, under certain conditions to reset all spinners to default values and ensure that onItemSelectedListener() is called for all.
Is it part of Android's semantics that onItemSelectedListener() is only called when user selection changes. Is there a way to force onItemSelectedListener() to be called?
If you want "onItemSelected" of Spinner to be fired, even if the item in the spinner is selected /if item selected and it is clicked again .
Then use this custom class which extends spinner ,this worked for me
Then edit your activity with spinners like this , I changed
static Spinner spinner1;
to
static NDSpinner spinner1;
and
variables.spinner1 = (Spinner) findViewById(R.id.spinner1);
to
variables.spinner1 = (NDSpinner ) findViewById(R.id.spinner1);
Also I changed the xml layout where the spinner is located
<Spinner
android:id="#+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/place" />
to
<com.yourpackagename.NDSpinner
android:id="#+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/place" />
Spinner extension class:
package com.yourpackagename;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Spinner;
import android.widget.Toast;
import java.lang.reflect.Field;
/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value.
* ie This is extended "Customized class of Spinner" to get the "onItemSelected" event even if the item in the
* Spinner is already selected by the user*/
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
private void ignoreOldSelectionByReflection() {
try {
Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);
reqField.setInt(this, -1);
} catch (Exception e) {
Log.d("Exception Private", "ex", e);
// TODO: handle exception
}
}
#Override
public void setSelection(int position, boolean animate)
{
boolean sameSelected = position == getSelectedItemPosition();
ignoreOldSelectionByReflection();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override
public void setSelection(int position) {
ignoreOldSelectionByReflection();
super.setSelection(position);
}
}
The default Spinner doesn't trigger any event when you select the same item as your currently selected item. You will need to make a custom Spinner in order to do this. See How can I get an event in Android Spinner when the current selected item is selected again?
Add the same adapter every time if you want to do it using default spinner :
#Override
public void onItemSelected(AdapterView adapter, View v, int position, long lng) {
spinner.setAdapter(adapter);
}
This is my class which is population items in a list view , things goins well , onItemClick method is executed when clicked on a listitem , but when i pass an intent from there , it is not passing the intent , plz help me out.
public class VideosListView extends ListView implements android.widget.AdapterView.OnItemClickListener {
private List<Video> videos;
private VideoClickListener videoClickListener;
MainActivity ma;
private Context mcontext;
public VideosListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VideosListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VideosListView(Context context) {
super(context);
mcontext=context;
}
public void setVideos(List<Video> videos){
this.videos = videos;
VideosAdapter adapter = new VideosAdapter(getContext(), videos);
setAdapter(adapter);
// When the videos are set we also set an item click listener to the list
// this will callback to our custom list whenever an item it pressed
// it will tell us what position in the list is pressed
setOnItemClickListener(this);
}
// Calling this method sets a listener to the list
// Whatever class is passed in will be notified when the list is pressed
// (The class that is passed in just has to 'implement VideoClickListener'
// meaning is has the methods available we want to call)
public void setOnVideoClickListener(VideoClickListener l) {
videoClickListener = l;
}
#Override
public void setAdapter(ListAdapter adapter)
{
super.setAdapter(adapter);
}
// When we receive a notification that a list item was pressed
// we check to see if a video listener has been set
// if it has we can then tell the listener 'hey a video has just been clicked' also passing the video
#Override
public void onItemClick(AdapterView<?> adapter, View v, int position, long id)
{
Intent intent = new Intent(mcontext,AnVideoView.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mcontext.startActivity(intent);
Log.i("VideoListView", "I am Clicked");
if(videoClickListener != null)
{
videoClickListener.onVideoClicked(videos.get(position));
Log.d("My Position ","position is" + position);
}
this is my classsnow from onItemClick() i want to pass to a activity class , how to do that thanx helping
Try This...
It will help you.
Activity activity;
public VideosListView(Activity activity) {
super(context);
this.activity=activity;
}
#Override
public void onItemClick(AdapterView<?> adapter, View v, int position, long id)
{
Intent intent = new Intent(activity,AnVideoView.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
Log.i("VideoListView", "I am Clicked");
if(videoClickListener != null)
{
videoClickListener.onVideoClicked(videos.get(position));
Log.d("My Position ","position is" + position);
}
in onItemClick((AdapterView adapter, View v, int position, long id)
i have created a contructor to the class extending BaseAdapter , and then from the there we can easily pass our intent... it is working for me , anyways thaks helping me a lot guys
we can pass the position in the contructor , and do whatever we want to do with the item selected.
I have an Android Spinner and I want to listen the event when the user press "Back Key" when the spinner's select panel is showing.I have implement the OnItemSelectedListener ,but the onNothingSelected(AdapterView arg0) was not invoked when press back key.
I just want to listen the event when user select nothing( or the select panel disappear) .
Is there a correct way to do this?
Thanks!
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.colors, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(adapter);
s1.setOnItemSelectedListener(
new OnItemSelectedListener() {
public void onItemSelected(
AdapterView<?> parent, View view, int position, long id) {
showToast("Spinner1: position=" + position + " id=" + id);
}
public void onNothingSelected(AdapterView<?> parent) {
showToast("Spinner1: unselected");
}
});
This is a sample in Android 2.2 SDK,it's also not show "Spinner1: unselected" when the select panel disappear.
It looks like you won't be able to do what you want without extending the Spinner class. It seems that Spinner doesn't register an OnCancelListener with the AlertDialog it builds to display the items.
Code from Spinner.java:
#Override
public boolean performClick() {
boolean handled = super.performClick();
if (!handled) {
handled = true;
Context context = getContext();
final DropDownAdapter adapter = new DropDownAdapter(getAdapter());
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (mPrompt != null) {
builder.setTitle(mPrompt);
}
mPopup = builder.setSingleChoiceItems(adapter, getSelectedItemPosition(), this).show();
}
return handled;
}
public void onClick(DialogInterface dialog, int which) {
setSelection(which);
dialog.dismiss();
mPopup = null;
}
Also, setSelection is only called when an item in the dialog is clicked. This won't be called when the user presses the back button since that is an OnCancel event.
Extending Spinner will be a bit of a pain since you have to copy everything back to AdapterView into your source from the android source since various member fields necessary for implementation are only exposed at the package level.
Another approach is to create a minimal custom spinner dropdown item, ie:
<com.mypackage.MyTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
/>
and then intercept onDetachedFromWindow():
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Callback here
}
}
You can finesse this if you use a custom ArrayAdapter to set only one of the dropdown items to do the callback, as well as setting
suitable context for the callback, etc.
Depending on what you do inside the callback, you may want to
post it as a runnable, so that the spinner is fully cleaned up
before it does anything.