Wie kann onItemSelected davon abgehalten werden, auf einem neu instanziierten Spinner abzufeuern?

StackOverflow https://stackoverflow.com/questions/2562248

Frage

Ich habe mir einige weniger als elegante Wege ausgedacht, um das zu lösen, aber ich weiß, dass mir etwas fehlen muss.

Mein onItemSelected wird sofort ohne Interaktion mit dem Benutzer ausgelöst, und dies ist unerwünschtes Verhalten.Ich möchte, dass die Benutzeroberfläche wartet, bis der Benutzer etwas auswählt, bevor sie etwas unternimmt.

Ich habe sogar versucht, den Hörer im einzurichten onResume(), in der Hoffnung, dass das helfen würde, aber das tut es nicht.

Wie kann ich verhindern, dass dies ausgelöst wird, bevor der Benutzer die Steuerung berühren kann?

public class CMSHome extends Activity { 

private Spinner spinner;

@Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Heres my spinner ///////////////////////////////////////////
    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    };

public void onResume() {
    super.onResume();
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}

    public class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {

     Intent i = new Intent(CMSHome.this, ListProjects.class);
     i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
        startActivity(i);

        Toast.makeText(parent.getContext(), "The pm is " +
          parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
    }

    public void onNothingSelected(AdapterView parent) {
      // Do nothing.
    }
}
}
War es hilfreich?

Lösung

Ich hätte erwartet, dass Ihre Lösung funktioniert - ich würde das Auswahlereignis nicht ausführen, wenn Sie den Adapter vor dem Einrichten des Hörers einstellen würden.

Trotzdem würde eine einfache boolesche Flagge es Ihnen ermöglichen, das Ereignis der ersten Auswahl des Schurkens zu erkennen und zu ignorieren.

Andere Tipps

Die Verwendung von Runnables ist völlig falsch.

Verwenden setSelection(position, false); in der ersten Auswahl vor setOnItemSelectedListener(listener)

Auf diese Weise setzen Sie Ihre Auswahl ohne Animation ein, wodurch der auf dem Element ausgewählte Listener aufgerufen wird. Aber der Zuhörer ist Null, also wird nichts ausgeführt. Dann wird Ihr Zuhörer zugewiesen.

Folgen Sie also genau dieser Sequenz:

Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);

Versuchen Sie unter Bezugnahme auf die Antwort von Dan Dyer, die zu registrieren OnSelectListener in einem post(Runnable) Methode:

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});

Auf das für mich trat das gewünschte Verhalten schließlich auf.

In diesem Fall bedeutet dies auch, dass der Hörer nur auf einen geänderten Gegenstand feuert.

Ich habe eine kleine Versorgungsmethode zum Ändern erstellt Spinner Auswahl, ohne den Benutzer zu benachrichtigen:

private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
    final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
    spinner.setOnItemSelectedListener(null);
    spinner.post(new Runnable() {
        @Override
        public void run() {
            spinner.setSelection(selection);
            spinner.post(new Runnable() {
                @Override
                public void run() {
                    spinner.setOnItemSelectedListener(l);
                }
            });
        }
    });
}

Es deaktiviert den Hörer, ändert die Auswahl und veranlasst den Hörer danach.

Der Trick ist, dass Anrufe für den UI -Thread asynchron sind. Sie müssen dies also in aufeinanderfolgenden Handler -Posts tun.

Leider scheint es, dass die beiden vorgeschlagenen Lösungen für dieses Problem, nämlich das Zählen von Rückrufvorkommen und die Veröffentlichung eines Runnable, um den Rückruf zu einem späteren Zeitpunkt festzulegen, fehlschlagen, wenn beispielsweise die Optionen zur Zugänglichkeit aktiviert sind. Hier ist eine Helferklasse, die sich um diese Probleme handelt. Weitere Explosionen finden Sie im Kommentarblock.

import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;

/**
 * Spinner Helper class that works around some common issues 
 * with the stock Android Spinner
 * 
 * A Spinner will normally call it's OnItemSelectedListener
 * when you use setSelection(...) in your initialization code. 
 * This is usually unwanted behavior, and a common work-around 
 * is to use spinner.post(...) with a Runnable to assign the 
 * OnItemSelectedListener after layout.
 * 
 * If you do not call setSelection(...) manually, the callback
 * may be called with the first item in the adapter you have 
 * set. The common work-around for that is to count callbacks.
 * 
 * While these workarounds usually *seem* to work, the callback
 * may still be called repeatedly for other reasons while the 
 * selection hasn't actually changed. This will happen for 
 * example, if the user has accessibility options enabled - 
 * which is more common than you might think as several apps 
 * use this for different purposes, like detecting which 
 * notifications are active.
 * 
 * Ideally, your OnItemSelectedListener callback should be
 * coded defensively so that no problem would occur even
 * if the callback was called repeatedly with the same values
 * without any user interaction, so no workarounds are needed.
 * 
 * This class does that for you. It keeps track of the values
 * you have set with the setSelection(...) methods, and 
 * proxies the OnItemSelectedListener callback so your callback
 * only gets called if the selected item's position differs 
 * from the one you have set by code, or the first item if you
 * did not set it.
 * 
 * This also means that if the user actually clicks the item
 * that was previously selected by code (or the first item
 * if you didn't set a selection by code), the callback will 
 * not fire.
 * 
 * To implement, replace current occurrences of:
 * 
 *     Spinner spinner = 
 *         (Spinner)findViewById(R.id.xxx);
 *     
 * with:
 * 
 *     SpinnerHelper spinner = 
 *         new SpinnerHelper(findViewById(R.id.xxx))
 *         
 * SpinnerHelper proxies the (my) most used calls to Spinner
 * but not all of them. Should a method not be available, use: 
 * 
 *      spinner.getSpinner().someMethod(...)
 *
 * Or just add the proxy method yourself :)
 * 
 * (Quickly) Tested on devices from 2.3.6 through 4.2.2
 * 
 * @author Jorrit "Chainfire" Jongma
 * @license WTFPL (do whatever you want with this, nobody cares)
 */
public class SpinnerHelper implements OnItemSelectedListener {
    private final Spinner spinner;

    private int lastPosition = -1;
    private OnItemSelectedListener proxiedItemSelectedListener = null;  

    public SpinnerHelper(Object spinner) {
         this.spinner = (spinner != null) ? (Spinner)spinner : null;        
    }

    public Spinner getSpinner() {
        return spinner;
    }

    public void setSelection(int position) { 
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position);     
    }

    public void setSelection(int position, boolean animate) {
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position, animate);        
    }

    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        proxiedItemSelectedListener = listener;
        spinner.setOnItemSelectedListener(listener == null ? null : this);
    }   

    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (position != lastPosition) {
            lastPosition = position;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onItemSelected(
                        parent, view, position, id
                );
            }
        }
    }

    public void onNothingSelected(AdapterView<?> parent) {
        if (-1 != lastPosition) {
            lastPosition = -1;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onNothingSelected(
                        parent
                );
            }
        }
    }

    public void setAdapter(SpinnerAdapter adapter) {
        if (adapter.getCount() > 0) {
            lastPosition = 0;
        }
        spinner.setAdapter(adapter);
    }

    public SpinnerAdapter getAdapter() { return spinner.getAdapter(); } 
    public int getCount() { return spinner.getCount(); }    
    public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); }   
    public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); }
    public Object getSelectedItem() { return spinner.getSelectedItem(); }
    public long getSelectedItemId() { return spinner.getSelectedItemId(); }
    public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); }
    public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); }
    public boolean isEnabled() { return spinner.isEnabled(); }
}

Ich hatte viele Probleme mit dem Spinner, das von dem Abfeuern, als ich nicht wollte, und alle Antworten hier sind unzuverlässig. Sie funktionieren - aber nur manchmal. Sie werden schließlich auf Szenarien stoßen, in denen sie versagen und Fehler in Ihren Code einführen.

Was für mich funktioniert hat, war, den letzten ausgewählten Index in einer Variablen zu speichern und im Hörer zu bewerten. Wenn es mit dem neuen ausgewählten Index nichts entspricht, tun Sie nichts und kehren Sie an, sonst fahren Sie mit dem Hörer fort. Mach das:

//Declare a int member variable and initialize to 0 (at the top of your class)
private int mLastSpinnerPosition = 0;

//then evaluate it in your listener
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

  if(mLastSpinnerPosition == i){
        return; //do nothing
  }

  mLastSpinnerPosition = i;
  //do the rest of your code now

}

Vertrauen Sie mir, wenn ich das sage, ist dies bei weitem die zuverlässigste Lösung. Ein Hack, aber es funktioniert!

Ich war in einer ähnlichen Situation und habe eine einfache Lösung für mich.

Es scheint Methoden zu sein setSelection(int position) und setSelected(int position, boolean animate) unterschiedliche interne Implementierung haben.

Wenn Sie die zweite Methode verwenden setSelected(int position, boolean animate) Mit einer falschen Animate -Flagge erhalten Sie die Auswahl ohne Schuss onItemSelected Hörer.

Nur um Hinweise darauf zu fleischigen, den OnTouchListener zu verwenden, um zwischen automatischen Aufrufen des setonItemSelectedIlneer (die Teil der Aktivitätsinitialisierung usw. sind) im Vergleich zu den durch die tatsächlichen Benutzerinteraktion ausgelösten Aufrufen, nachdem ich hier und hier einige andere Vorschläge ausprobiert habe und ausgelöst wurde, und hier und hier und hier ausgelöst werden, und hier und hier ausgelöst werden fand, dass es gut mit den wenigsten Codezeilen funktioniert hat.

Stellen Sie einfach ein Boolean -Feld für Ihre Aktivität/Ihr Fragment fest:

private Boolean spinnerTouched = false;

Kurz bevor Sie den SetonItemSETEM -Listener Ihres Spinners eingestellt haben, stellen Sie einen OnTouchListener fest:

    spinner.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            System.out.println("Real touch felt.");
            spinnerTouched = true;
            return false;
        }
    });

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    ...
         if (spinnerTouched){
         //Do the stuff you only want triggered by real user interaction.
        }
        spinnerTouched = false;
spinner.setSelection(Adapter.NO_SELECTION, false);

Nachdem ich jetzt schon lange meine Haare herausgezogen habe, habe ich meine eigene Spinnerklasse erstellt. Ich habe eine Methode hinzugefügt, die den Hörer entsprechend abtrennt und verbindet.

public class SaneSpinner extends Spinner {
    public SaneSpinner(Context context) {
        super(context);
    }

    public SaneSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SaneSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    // set the ceaseFireOnItemClickEvent argument to true to avoid firing an event
    public void setSelection(int position, boolean animate, boolean ceaseFireOnItemClickEvent) {
        OnItemSelectedListener l = getOnItemSelectedListener();
        if (ceaseFireOnItemClickEvent) {
            setOnItemSelectedListener(null);
        }

        super.setSelection(position, animate);

        if (ceaseFireOnItemClickEvent) {
            setOnItemSelectedListener(l);
        }
    }
}

Verwenden Sie es in Ihrem XML wie folgt:

<my.package.name.SaneSpinner
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/mySaneSpinner"
    android:entries="@array/supportedCurrenciesFullName"
    android:layout_weight="2" />

Alles, was Sie tun müssen, ist, die Instanz von Swespinner nach der Inflation und nach der Auswahl wie folgt aufzurufen:

mMySaneSpinner.setSelection(1, true, true);

Damit wird kein Ereignis abgefeuert und die Benutzerinteraktion wird nicht unterbrochen. Dies reduzierte meine Codekomplexität sehr. Dies sollte in Stock Android enthalten sein, da es sich wirklich um eine Pita handelt.

Keine unerwünschten Ereignisse aus der Layoutphase, wenn Sie den Hörer hinzufügen, bis das Layout fertig ist:

spinner.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ensure you call it only once works for JELLY_BEAN and later
            spinner.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            // add the listener
            spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                    // check if pos has changed
                    // then do your work
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                }

            });

        }
    });

Dies geschieht, wenn Sie eine Auswahl in Code als treffen;

   mSpinner.setSelection(0);

Anstelle der obigen Anweisung verwendet

   mSpinner.setSelection(0,false);//just simply do not animate it.

Bearbeiten: Diese Methode funktioniert nicht für Mi Android Version MI UI.

Ich habe eine sehr einfache Antwort, 100% sicher, dass es funktioniert:

boolean Touched=false; // this a a global variable

public void changetouchvalue()
{
   Touched=true;
}

// this code is written just before onItemSelectedListener

 spinner.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            System.out.println("Real touch felt.");
            changetouchvalue();
            return false;
        }
    });

//inside your spinner.SetonItemSelectedListener , you have a function named OnItemSelected iside that function write the following code

if(Touched)
{
 // the code u want to do in touch event
}

Ich habe viel elegantere Lösung dafür gefunden. Es beinhaltet das Zählen, wie oft der Arrayadapter (in Ihrem Fall "Adapter") aufgerufen wurde. Nehmen wir an, Sie haben 1 Spinner und rufen an:

int iCountAdapterCalls = 0;

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

Deklarieren Sie einen Int -Zähler nach der OnCreate und dann in der ONITEMSETEMSECTECT () -Methode, um zu überprüfen, wie oft das Atapter aufgerufen wurde. In Ihrem Fall haben Sie es nur einmal so angerufen:

if(iCountAdapterCalls < 1)
{
  iCountAdapterCalls++;
  //This section executes in onCreate, during the initialization
}
else
{
  //This section corresponds to user clicks, after the initialization
}

Mein kleiner Beitrag ist eine Variation einiger der oben genannten, die ein paar Mal zu mir geeignet sind.

Deklarieren Sie eine Ganzzahlvariable als Standardwert (oder zuletzt in den Vorlieben gespeicherten Gebrauchtwert). Verwenden Sie Spinner.SetSelection (MyDefault), um diesen Wert festzulegen, bevor der Hörer registriert ist. Überprüfen Sie, ob der neue Spinnerwert dem Wert des Wertes entspricht, den Sie zugewiesen haben, bevor Sie einen weiteren Code ausführen.

Dies hat den hinzugefügten Vorteil, Code nicht auszuführen, wenn der Benutzer denselben Wert erneut auswählt.

Nachdem ich das gleiche Problem hatte, kam ich mit Tags zu diesen Lösungen. Die Idee dahinter ist einfach: Wenn der Spinner programmatisch geändert wird, stellen Sie sicher, dass das Tag die ausgewählte Position widerspiegelt. Im Hörer prüfen Sie, ob die ausgewählte Position dem Tag entspricht. Wenn dies der Fall ist, wurde die Spinnerauswahl programmatisch geändert.

Unten ist meine neue "Spinner -Proxy" -Klasse:

package com.samplepackage;

import com.samplepackage.R;
import android.widget.Spinner;

public class SpinnerFixed {

    private Spinner mSpinner;

    public SpinnerFixed(View spinner) {
         mSpinner = (Spinner)spinner;
         mSpinner.setTag(R.id.spinner_pos, -2);
    }

    public boolean isUiTriggered() {
         int tag = ((Integer)mSpinner.getTag(R.id.spinner_pos)).intValue();
         int pos = mSpinner.getSelectedItemPosition();
         mSpinner.setTag(R.id.spinner_pos, pos);
         return (tag != -2 && tag != pos);
    }

    public void setSelection(int position) {
        mSpinner.setTag(R.id.spinner_pos, position);
        mSpinner.setSelection(position);
    }

    public void setSelection(int position, boolean animate) {
        mSpinner.setTag(R.id.spinner_pos, position);
        mSpinner.setSelection(position, animate);
    }

    // If you need to proxy more methods, use "Generate Delegate Methods"
    // from the context menu in Eclipse.
}

Sie benötigen auch eine XML -Datei mit dem Tag -Setup in Ihrem Values Verzeichnis. Ich habe meine Datei benannt spinner_tag.xml, Aber das liegt an dir. Es sieht aus wie das:

<resources xmlns:android="http://schemas.android.com/apk/res/android">
  <item name="spinner_pos" type="id" />
</resources>

Jetzt ersetzen

Spinner myspinner;
...
myspinner = (Spinner)findViewById(R.id.myspinner);

in Ihrem Code mit

SpinnerFixed myspinner;
...
myspinner = new SpinnerFixed(findViewById(R.id.myspinner));

Und lassen Sie Ihren Händler etwas so aussehen:

myspinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (myspinner.isUiTriggered()) {
            // Code you want to execute only on UI selects of the spinner
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});

Die Funktion isUiTriggered() wird wahr zurückkehren, wenn der Spinner vom Benutzer geändert wurde. Beachten Sie, dass diese Funktion einen Nebeneffekt hat - sie wird das Tag festgelegt, sodass ein zweiter Aufruf im selben Listener -Anruf immer zurückgibt false.

Dieser Wrapper wird auch das Problem behandeln, wobei der Hörer während der Layout -Erstellung aufgerufen wird.

Viel Spaß, Jens.

Da nichts für mich funktioniert hat und ich mehr als einen Spinner in meiner Ansicht habe (und IMHO, das eine Bool -Karte hält, ist ein Overkill). Ich verwende das Tag, um die Klicks zu zählen:

spinner.setTag(0);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            Integer selections = (Integer) parent.getTag();
            if (selections > 0) {
                // real selection
            }
            parent.setTag(++selections); // (or even just '1')
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });

Viele Antworten schon, hier ist meins.

Ich verlängere mich AppCompatSpinner und fügen Sie eine Methode hinzu pgmSetSelection(int pos) Dadurch können Sie die programmatische Auswahleinstellung ohne Auslösen eines Auswahl -Rückrufs auslösen. Ich habe dies mit rxjava codiert, damit die Auswahlereignisse über eine geliefert werden Observable.

package com.controlj.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;

import io.reactivex.Observable;

/**
 * Created by clyde on 22/11/17.
 */

public class FilteredSpinner extends android.support.v7.widget.AppCompatSpinner {
    private int lastSelection = INVALID_POSITION;


    public void pgmSetSelection(int i) {
        lastSelection = i;
        setSelection(i);
    }

    /**
     * Observe item selections within this spinner. Events will not be delivered if they were triggered
     * by a call to setSelection(). Selection of nothing will return an event equal to INVALID_POSITION
     *
     * @return an Observable delivering selection events
     */
    public Observable<Integer> observeSelections() {
        return Observable.create(emitter -> {
            setOnItemSelectedListener(new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                    if(i != lastSelection) {
                        lastSelection = i;
                        emitter.onNext(i);
                    }
                }

                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {
                    onItemSelected(adapterView, null, INVALID_POSITION, 0);
                }
            });
        });
    }

    public FilteredSpinner(Context context) {
        super(context);
    }

    public FilteredSpinner(Context context, int mode) {
        super(context, mode);
    }

    public FilteredSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
        super(context, attrs, defStyleAttr, mode);
    }
}

Ein Beispiel für die Verwendung, genannt in onCreateView() in einem Fragment zum Beispiel:

    mySpinner = view.findViewById(R.id.history);
    mySpinner.observeSelections()
        .subscribe(this::setSelection);

wo setSelection() ist eine Methode in der umschließenden Ansicht, die so aussieht und die beide von Benutzerauswahlereignissen über die genannt wird Observable und auch an anderer Stelle programmgesteuert, sodass die Logik für die Handhabung von Auswahlmethoden üblich ist.

private void setSelection(int position) {
    if(adapter.isEmpty())
        position = INVALID_POSITION;
    else if(position >= adapter.getCount())
        position = adapter.getCount() - 1;
    MyData result = null;
    mySpinner.pgmSetSelection(position);
    if(position != INVALID_POSITION) {
        result = adapter.getItem(position);
    }
    display(result);  // show the selected item somewhere
}

Ich würde versuchen anzurufen

spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());

Nach dem Anruf setAdapter (). Versuchen Sie auch, vor dem Adapter anzurufen.

Sie haben immer die Lösung für die Unterklasse, bei der Sie eine booleale Flagge mit Ihrer Overiden -SetAdapter -Methode einwickeln können, um das Ereignis zu überspringen.

Die Lösung mit einer Booleschen Flagge oder einem Zähler hat mir nicht geholfen, 'Ursache während der Orientierung ändere ONITEMSETELT () "überfliege" die Flagge oder den Zähler.

Ich habe unterklassifiziert android.widget.Spinner und winzige Ergänzungen gemacht. Die relevanten Teile sind unten. Diese Lösung hat für mich funktioniert.

private void setHandleOnItemSelected()
{
  final StackTraceElement [] elements = Thread.currentThread().getStackTrace();

  for (int index = 1; index < elements.length; index++)
  {
     handleOnItemSelected = elements[index].toString().indexOf("PerformClick") != -1; //$NON-NLS-1$

     if (handleOnItemSelected)
     {
        break;
     }
  }
}

@Override
public void setSelection(int position, boolean animate)
{
  super.setSelection(position, animate);

  setHandleOnItemSelected();
}

@Override
public void setSelection(int position)
{
  super.setSelection(position);

  setHandleOnItemSelected();
}

public boolean shouldHandleOnItemSelected()
{
  return handleOnItemSelected;
}

Dies ist auch keine elegante Lösung. Tatsächlich ist es eher Rube-Goldberg, aber es scheint zu funktionieren. Ich stelle sicher, dass der Spinner mindestens einmal verwendet wurde, indem der Array -Adapter erweitert und seine GetDropdownView überschrieben wird. In der neuen GetDropdownView -Methode habe ich ein boolescher Flag, das mindestens einmal verwendet wird, um das Dropdown -Menü anzuzeigen. Ich ignoriere Anrufe an den Hörer, bis das Flag eingestellt ist.

MainActivity.oncreate ():

ActionBar ab = getActionBar();
ab.setDisplayShowTitleEnabled(false);
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
ab.setListNavigationCallbacks(null, null);

ArrayList<String> abList = new ArrayList<String>();
abList.add("line 1");
...

ArAd  abAdapt = new ArAd (this
   , android.R.layout.simple_list_item_1
   , android.R.id.text1, abList);
ab.setListNavigationCallbacks(abAdapt, MainActivity.this);

Überschreiben Sie das Array -Adapter:

private static boolean viewed = false;
private class ArAd extends ArrayAdapter<String> {
    private ArAd(Activity a
            , int layoutId, int resId, ArrayList<String> list) {
        super(a, layoutId, resId, list);
        viewed = false;
    }
    @Override
    public View getDropDownView(int position, View convertView,
            ViewGroup parent) {
        viewed = true;
        return super.getDropDownView(position, convertView, parent);
    }
}

Modifizierter Hörer:

@Override
public boolean onNavigationItemSelected(
   int itemPosition, long itemId) {
   if (viewed) {
     ...
   }
   return false;
}

Wenn Sie Aktivitäten im laufenden Fliegen nachbilden müssen, z. B. das Ändern von Themen, funktioniert eine einfache Flagge/Zähler nicht

Verwenden Sie die Funktion von OnuserInterInteraction (), um die Benutzeraktivität zu erkennen.

Hinweis : https://stackoverflow.com/a/25070696/4772917

Ich habe erledigt mit einfachster Art:

private AdapterView.OnItemSelectedListener listener;
private Spinner spinner;

OnCreate ();

spinner = (Spinner) findViewById(R.id.spinner);

listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {

            Log.i("H - Spinner selected position", position);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    };

 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            spinner.setOnItemSelectedListener(listener);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

Fertig

if () {        
       spinner.setSelection(0);// No reaction to create spinner !!!
     } else {
        spinner.setSelection(intPosition);
     }


spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

         if (position > 0) {
           // real selection
         }

      }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

     }
});

Ich könnte die Lösung meines Problems erhalten, indem ich die Breite mit 2 multipliziert, mit 2, die den Code ergab: generasacodicetagpre.

Ich muss verwenden mSpinner im Vieweholder so die Flagge mOldPosition befindet sich in der anonymen inneren Klasse.

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            int mOldPosition = mSpinner.getSelectedItemPosition();

            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long l) {
                if (mOldPosition != position) {
                    mOldPosition = position;
                    //Do something
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
                //Do something
            }
        });

Ich würde den Anfangsindex während der Erstellung des OnClickListener Objekts speichern.

   int thisInitialIndex = 0;//change as needed

   myspinner.setSelection(thisInitialIndex);

   myspinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

      int initIndex = thisInitialIndex;

      @Override
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         if (id != initIndex) { //if selectedIndex is the same as initial value
            // your real onselecteditemchange event
         }
      }

      @Override
      public void onNothingSelected(AdapterView<?> parent) {
      }
  });

Meine Lösung verwendet onTouchListener schränkt aber seine Verwendung nicht ein.Es erstellt einen Wrapper für onTouchListener bei Bedarf wo einrichten onItemSelectedListener.

public class Spinner extends android.widget.Spinner {
    /* ...constructors... */

    private OnTouchListener onTouchListener;
    private OnItemSelectedListener onItemSelectedListener;

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        onItemSelectedListener = listener;
        super.setOnTouchListener(wrapTouchListener(onTouchListener, onItemSelectedListener));
    }

    @Override
    public void setOnTouchListener(OnTouchListener listener) {
        onTouchListener = listener;
        super.setOnTouchListener(wrapTouchListener(onTouchListener, onItemSelectedListener));
    }

    private OnTouchListener wrapTouchListener(final OnTouchListener onTouchListener, final OnItemSelectedListener onItemSelectedListener) {
        return onItemSelectedListener != null ? new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Spinner.super.setOnItemSelectedListener(onItemSelectedListener);
                return onTouchListener != null && onTouchListener.onTouch(view, motionEvent);
            }
        } : onTouchListener;
    }
}

Ich antworte vielleicht zu spät über den Beitrag Android -Datenbank . Ich habe eine benutzerdefinierte Bindung erstellt, um sicherzustellen, dass der Listener erst dann aufgerufen wird, wenn das ausgewählte Element geändert wurde. Selbst wenn der Benutzer die gleiche Position immer wieder auswählt, wird das Ereignis nicht abgefeuert.

Layout XML -Datei

    <layout>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
xmlns:app="http://schemas.android.com/apk/res-auto">


<Spinner
    android:id="@+id/spinner"
    android:layout_width="150dp"
    android:layout_height="wrap_content"
    android:spinnerMode="dropdown"
    android:layout_below="@id/member_img"
    android:layout_marginTop="@dimen/activity_vertical_margin"
    android:background="@drawable/member_btn"
    android:padding="@dimen/activity_horizontal_margin"
    android:layout_marginStart="@dimen/activity_horizontal_margin"
    android:textColor="@color/colorAccent"
    app:position="@{0}"
    />
 </RelativeLayout>
 </layout>

app:position dort, wo Sie die Position übergeben, um auszuwählen.

Benutzerdefinierte Bindung

  @BindingAdapter(value={ "position"}, requireAll=false)
  public static void setSpinnerAdapter(Spinner spinner, int selected) 
  {

    final int [] selectedposition= new int[1];
    selectedposition[0]=selected;


    // custom adapter or you can set default adapter
        CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(spinner.getContext(), <arraylist you want to add to spinner>);
        spinner.setAdapter(customSpinnerAdapter);
            spinner.setSelection(selected,false);


    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String item = parent.getItemAtPosition(position).toString();
        if( position!=selectedposition[0]) {
                        selectedposition[0]=position;
            // do your stuff here
                    }
                }


        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });
}

Weitere Informationen zur benutzerdefinierten Datenbindung finden Sie hier Android Custom Setter

HINWEIS

  1. Vergessen Sie nicht, die Datenbank in Ihrer Gradle -Datei zu aktivieren

       android {
     ....
     dataBinding {
     enabled = true
    }
    }
    
  2. Geben Sie Ihre Layoutdateien in ein <layout> Stichworte

mYear.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View arg1, int item, long arg3) {
                if (mYearSpinnerAdapter.isEnabled(item)) {

                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top