Как сохранить onItemSelected от стрельбы по вновь созданной Spinner?
Я подумал о некоторых менее элегантных способах решения этого вопроса, но я знаю, что мне что-то не хватает.
My onItemSelected
срабатывает немедленно без какого-либо взаимодействия с пользователем, и это нежелательное поведение. Я хочу, чтобы пользовательский интерфейс подождал, пока пользователь ничего не выберет, прежде чем что-нибудь сделает.
Я даже попытался настроить слушателя в onResume()
, надеясь, что это поможет, но это не так.
Как я могу остановить это от срабатывания, прежде чем пользователь сможет коснуться элемента управления?
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.
}
}
}
Ответы
Ответ 1
Я бы ожидал, что ваше решение будет работать - хотя событие выбора не срабатывало, если вы настроили адаптер перед настройкой слушателя.
При этом простой логический флаг позволит вам обнаружить первое событие выбора изгоев и проигнорировать его.
Ответ 2
Использование Runnables полностью неверно.
Используйте setSelection(position, false);
в первоначальном выборе до setOnItemSelectedListener(listener)
Таким образом, вы устанавливаете свой выбор без анимации, из-за чего вызывается вызываемый элемент, выбранный по элементу. Но слушатель равен нулю, поэтому ничего не запускается. Затем назначается ваш слушатель.
Итак, следуйте этой точной последовательности:
Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);
Ответ 3
Ссылаясь на ответ Дэна Дайера, попробуйте зарегистрировать метод OnSelectListener
в post(Runnable)
:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
Сделав это для меня, наконец, произошло желаемое поведение.
В этом случае это также означает, что прослушиватель запускается только на измененном элементе.
Ответ 4
Я создал небольшой метод утилиты для изменения выбора Spinner
без уведомления пользователя:
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);
}
});
}
});
}
Отключает прослушиватель, изменяет выбор и снова включает слушателя.
Фокус в том, что вызовы асинхронны с потоком пользовательского интерфейса, поэтому вам нужно делать это в последовательных сообщениях обработчика.
Ответ 5
К сожалению, кажется, что два наиболее часто предлагаемых решения этой проблемы, а именно подсчет обратных вызовов и отправка Runnable для установки обратного вызова в более позднее время, могут быть неудачными, если, например, включены опции доступности. Здесь используется вспомогательный класс, который работает над этими проблемами. Дальнейшее объяснение находится в блоке комментариев.
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 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 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(); }
}
Ответ 6
У меня было много проблем с запуском spinner, когда я этого не хотел, и все ответы здесь ненадежны. Они работают, но только иногда. Вы в конечном итоге столкнетесь с сценариями, в которых они потерпят неудачу, и вносят ошибки в ваш код.
Что сработало для меня, так это сохранить последний выбранный индекс в переменной и оценить его в слушателе. Если это то же самое, что и новый выбранный индекс ничего не делать и возвращать, продолжайте прослушивать. Сделайте это:
//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
}
Поверьте мне, когда я скажу это, это, безусловно, самое надежное решение. Взлом, но он работает!
Ответ 7
Я был в похожей ситуации, и у меня есть простое решение, работающее для меня.
Похоже, что методы setSelection(int position)
и setSelected(int position, boolean animate)
имеют разную внутреннюю реализацию.
Когда вы используете второй метод setSelected(int position, boolean animate)
с флагом флага animate, вы получаете выделение без запуска onItemSelected
прослушивателя.
Ответ 8
Просто для определения подсказок при использовании onTouchListener для различения автоматических вызовов с помощью setOnItemSelectedListener (которые являются частью инициализации Activity и т.д.) против вызовов, вызванных фактическим взаимодействием с пользователем, я сделал следующее, попробовав другое предложения здесь и обнаружили, что он хорошо работает с наименьшими строками кода.
Просто установите логическое поле для вашего Activity/Fragment, например:
private Boolean spinnerTouched = false;
Затем перед установкой spinner setOnItemSelectedListener установите onTouchListener:
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;
Ответ 9
spinner.setSelection(Adapter.NO_SELECTION, false);
Ответ 10
Потянув мои волосы уже давно, я создал свой собственный класс Spinner. Я добавил метод, который отключает и подключает слушателя соответствующим образом.
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);
}
}
}
Используйте его в своем XML следующим образом:
<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" />
Все, что вам нужно сделать, - это получить экземпляр SaneSpinner после выбора уровня инфляции и набора вызовов следующим образом:
mMySaneSpinner.setSelection(1, true, true);
При этом ни одно событие не запускается, и взаимодействие пользователя не прерывается. Это значительно сократило мою сложность кода. Это должно быть включено в акции Android, так как это действительно PITA.
Ответ 11
Нет нежелательных событий на этапе компоновки, если вы отложите добавление слушателя до завершения макета:
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) {
}
});
}
});
Ответ 12
Я получил очень простой ответ, 100% уверен, что он работает:
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
}
Ответ 13
Я нашел гораздо более элегантное решение. Это связано с подсчетом того, сколько раз вызывается ArrayAdapter (в вашем случае "адаптер" ). Скажем, у вас есть 1 прядильщик, и вы звоните:
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);
Объявите счетчик int после метода onCreate, а затем внутри метода onItemSelected() установите условие "если", чтобы проверить, сколько раз был вызван адаптер. В вашем случае вы вызываете его только один раз:
if(iCountAdapterCalls < 1)
{
iCountAdapterCalls++;
//This section executes in onCreate, during the initialization
}
else
{
//This section corresponds to user clicks, after the initialization
}
Ответ 14
Мой небольшой вклад - это вариация на некоторые из вышеперечисленных, которые мне несколько раз подходили.
Объявить целочисленную переменную как значение по умолчанию (или последнее использованное значение, сохраненное в настройках).
Используйте spinner.setSelection(myDefault), чтобы установить это значение до регистрации слушателя.
В onItemSelected проверьте, соответствует ли новое значение spinner значению, которое вы назначили, перед запуском какого-либо дополнительного кода.
У этого есть дополнительное преимущество не запускать код, если пользователь снова выбирает одно и то же значение.
Ответ 15
После такой же проблемы я пришел к этим решениям, используя теги.
Идея этого проста: всякий раз, когда счетчик изменяется программно, убедитесь, что тег отражает выбранную позицию. В слушателе вы проверяете, соответствует ли выбранная позиция тегу. Если это так, выбор счетчика был изменен программно.
Ниже приведен мой новый класс "spinner proxy":
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.
}
Вам также понадобится XML файл с настройкой тега в вашем каталоге Values
.
Я назвал свой файл spinner_tag.xml
, но это до вас.
Это выглядит так:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="spinner_pos" type="id" />
</resources>
Теперь замените
Spinner myspinner;
...
myspinner = (Spinner)findViewById(R.id.myspinner);
в вашем коде с помощью
SpinnerFixed myspinner;
...
myspinner = new SpinnerFixed(findViewById(R.id.myspinner));
И сделайте ваш обработчик несколько похожим на это:
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) {
}
});
Функция isUiTriggered()
вернет значение true, если и только если счетчик был изменен пользователем. Обратите внимание, что эта функция имеет побочный эффект - она установит тег, поэтому второй вызов в том же вызове прослушивателя всегда будет возвращать false
.
Эта оболочка также будет обрабатывать проблему при вызове слушателя во время создания макета.
Удачи,
Jens.
Ответ 16
Так как для меня ничего не работало, и у меня на моем счету более 1 счетчик (и IMHO, содержащий карту bool, является излишним), я использую тег для подсчета кликов:
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) {
}
});
Ответ 17
Это произойдет, если вы делаете выбор в коде как:
mSpinner.setSelection(0);
Вместо указанного выше выражения используйте
mSpinner.setSelection(0,false);//just simply do not animate it.
Изменить: этот метод не работает для Mi Android Version Mi UI.
Ответ 18
Множество ответов уже, здесь мое.
Я расширяю AppCompatSpinner
и добавляю метод pgmSetSelection(int pos)
, который позволяет установить программный выбор без запуска обратного вызова выбора. Я закодировал это с помощью RxJava, чтобы события выбора доставлялись через 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);
}
}
Пример его использования, называемый onCreateView()
в Fragment
, например:
mySpinner = view.findViewById(R.id.history);
mySpinner.observeSelections()
.subscribe(this::setSelection);
где setSelection()
- это метод в представлении, который выглядит так, и который вызван как из событий выбора пользователя через Observable
, так и в другом месте программно, поэтому логика обработки выборки является общей для обоих методов выбора.
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
}
Ответ 19
Я бы попробовал позвонить
spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
после вызова setAdapter(). Также попробуйте позвонить перед адаптером.
У вас всегда есть решение пойти с подклассом, где вы можете привязать булевский флаг к вашему методу override setAdapter, чтобы пропустить событие.
Ответ 20
Решение с булевым флагом или счетчиком не помогло мне, потому что во время изменения ориентации onItemSelected() вызывает "overllew" флаг или счетчик.
Я подклассифицировал android.widget.Spinner
и сделал крошечные дополнения. Ниже приведены соответствующие части. Это решение сработало для меня.
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;
}
Ответ 21
Это тоже не изящное решение. На самом деле это скорее Рубе-Голдберг, но, похоже, он работает. Я убеждаюсь, что счетчик использовался хотя бы один раз, расширив адаптер массива и переопределив его getDropDownView. В новом методе getDropDownView у меня есть логический флаг, который установлен для отображения выпадающего меню, которое использовалось хотя бы один раз. Я игнорирую вызовы слушателю до тех пор, пока не будет установлен флаг.
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);
перезагрузить адаптер массива:
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);
}
}
измененный прослушиватель:
@Override
public boolean onNavigationItemSelected(
int itemPosition, long itemId) {
if (viewed) {
...
}
return false;
}
Ответ 22
если вам нужно воссоздать активность "на лету", например: изменение тем, простой флаг/счетчик не работает
использовать функцию onUserInteraction() для обнаружения активности пользователя,
ссылка: fooobar.com/questions/19093/...
Ответ 23
У меня сделано простейшим способом:
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) {
}
});
Готово
Ответ 24
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) {
}
});
Ответ 25
Это мое окончательное и простое в использовании решение:
public class ManualSelectedSpinner extends Spinner {
//get a reference for the internal listener
private OnItemSelectedListener mListener;
public ManualSelectedSpinner(Context context) {
super(context);
}
public ManualSelectedSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ManualSelectedSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
mListener = listener;
super.setOnItemSelectedListener(listener);
}
public void setSelectionWithoutInformListener(int position){
super.setOnItemSelectedListener(null);
super.setSelection(position);
super.setOnItemSelectedListener(mListener);
}
public void setSelectionWithoutInformListener(int position, boolean animate){
super.setOnItemSelectedListener(null);
super.setSelection(position, animate);
super.setOnItemSelectedListener(mListener);
}
}
Используйте по умолчанию setSelection(...)
для поведения по умолчанию или используйте setSelectionWithoutInformListener(...)
для выбора элемента в счетчике без запуска обратного вызова OnItemSelectedListener.
Ответ 26
Мне нужно использовать mSpinner
в ViewHolder, поэтому флаг mOldPosition
установлен в анонимном внутреннем классе.
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
}
});
Ответ 27
Я бы сохранил начальный индекс во время создания объекта onClickListener.
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) {
}
});
Ответ 28
Мое решение использует onTouchListener
, но не ограничивает его использование. Он создает оболочку для onTouchListener
, если необходимо, где setup 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;
}
}
Ответ 29
Возможно, я слишком поздно ответил на этот пост, однако мне удалось добиться этого, используя библиотеку привязки данных Android Android Databinding. Я создал настраиваемую привязку, чтобы убедиться, что прослушиватель не вызывается до тех пор, пока выбранный элемент не будет изменен, поэтому даже если пользователь снова и снова выбирает одну и ту же позицию, событие не запускается.
Макет xml файла
<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
- это место, в котором вы выбираете позицию.
Пользовательская привязка
@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) {
}
});
}
Подробнее о привязке пользовательских данных вы можете прочитать здесь Пользовательский сеттер Android
Примечание
-
Не забудьте включить привязку данных в файле Gradle
android {
....
dataBinding {
enabled = true
}
}
-
Включите файлы макета в теги <layout>
Ответ 30
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) {
}
});