Intereting Posts
Android L Preview не ищет собственные библиотеки в папке «armeabi» (UnsatisfiedLinkError) Log messages processIncoming, handlePacket, sendBufferedRequest повторяется LOT – андроид Android. При использовании LocationManager.requestLocationUpdates мне нужен WakeLock? Как вы можете продолжить прокрутку ScrollView при добавлении детей? Bluetooth-периферия ADVERTISE_FAILED_DATA_TOO_LARGE Отказался от загрузки сценария, поскольку он нарушает следующую политику политики безопасности контента Получение ошибки «Требуется версия Gradle 1.10. Текущая версия 1.12. "При выполнении" обертки градации "? Открыть адрес Facebook с помощью Facebook Android-приложение для телефона и планшета: 1 или 2 приложения? Репозиторий виртуальных устройств Android Отправка радиочастотных (RF) сигналов с Android-приложением Android Studio: установка завершилась неудачно, поскольку APK не был подписан Использование API распознавания речи Android из Google Glass Как прокрутить экран (я имею в виду, как перемещать экран) Доступ к ресурсам без контекста

Как использовать Android Spinner как раскрывающийся список

Мне потребовалось немало времени, чтобы окунуться в Android Spinner. После нескольких неудачных попыток реализации и после прочтения многих вопросов, частично похожих на мои собственные, но без удовлетворительных ответов , а некоторые без каких-либо ответов вообще, например здесь и здесь , я наконец понял, что «spinner» в Android не предназначен для То же самое, что и «раскрывающийся список» из настольных приложений или выбор в HTML. Однако то, что мое приложение (и я угадываю приложения всех других плакатов, чьи вопросы похожи) нуждается в том, что работает как раскрывающийся список, а не как прядильщик.

Мои две проблемы связаны с тем, что я сначала считал идиосинхронизмом OnItemSelectedListener (я видел их как отдельные вопросы на этом сайте, но не как один):

  1. Первоначальный выбор первого элемента списка запускается автоматически без взаимодействия пользователя.
  2. Когда элемент, который был уже выбран, снова выбран пользователем, он игнорируется.

Теперь я понимаю, что, когда вы думаете об этом, имеет смысл, чтобы это произошло на счетчике – он должен начинаться с выбранного значения по умолчанию, и вы вращаете его только для изменения этого значения, а не для «повторного выбора» Value – в документации фактически сказано: «Этот обратный вызов вызывается только тогда, когда вновь выбранная позиция отличается от ранее выбранной позиции». И я видел ответы, предлагающие установить флаг, чтобы игнорировать первый автоматический выбор – я думаю, я мог бы жить с этим, если нет другого пути.

Но поскольку я действительно хочу, это раскрывающийся список, который ведет себя как раскрывающийся список (и, как пользователи могут и должны ожидать), мне нужно что-то вроде Spinner, который ведет себя как раскрывающийся список, например, комбо -Box. Меня не волнует какой-либо автоматический предварительный выбор (это должно произойти без запуска моего слушателя), и я хочу знать о каждом выборе, даже если он такой же, как и раньше (в конце концов, пользователь снова выбрал тот же элемент) ,

Итак … есть ли что-то в Android, которое может это сделать, или какое-то обходное решение, чтобы заставить Spinner вести себя как раскрывающийся список? Если на этом сайте есть такой вопрос, который я не нашел и который имеет удовлетворительный ответ, сообщите мне (в этом случае я искренне извиняюсь за повторение вопроса).

Solutions Collecting From Web of "Как использовать Android Spinner как раскрывающийся список"

+1 к ответу Дэвида. Тем не менее, вот предложение реализации, которое не связано с копированием кода из источника (который, кстати, выглядит точно так же, как Дэвид, опубликованный в 2.3 ):

@Override void setSelectionInt(int position, boolean animate) { mOldSelectedPosition = INVALID_POSITION; super.setSelectionInt(position, animate); } 

Таким образом вы будете обманывать родительский метод, считая, что это новая позиция каждый раз.

В качестве альтернативы вы можете попытаться установить положение недействительным при щелчке по onNothingSelected и установке его в onNothingSelected . Это не так хорошо, потому что пользователь не увидит, какой элемент выбран во время диалога.

Хорошо, я думаю, что придумал решение для моей собственной ситуации с помощью ответа Дэвида и Феликса (я считаю, что Дэвид помог Феликсу, который, в свою очередь, помог мне). Я думал, что отправлю его здесь вместе с образцом кода, если кто-то еще найдет этот подход полезным. Он также решает обе мои проблемы (как нежелательный автоматический выбор, так и желаемый триггер повторного выбора).

То, что я сделал, добавлено « пожалуйста, выберите » фиктивный элемент в качестве первого элемента в моем списке (изначально просто обойти проблему автоматического выбора, чтобы я мог игнорировать, когда он был выбран без взаимодействия с пользователем), а затем, когда другой Элемент выбран, и я обработал выделение, я просто сбросил счетчик на фиктивный элемент (который игнорируется). Подумайте об этом, я должен был подумать об этом задолго до того, как решился опубликовать свой вопрос на этом сайте, но все это всегда более очевидно в ретроспективе … и я обнаружил, что написание моего вопроса действительно помогло мне задуматься о том, что Я хотел достичь.

Очевидно, что если наличие фиктивного элемента не соответствует вашей ситуации, это может быть не идеальным решением для вас, но поскольку я хотел был инициировать действие, когда пользователь выбрал значение (и чтобы значение оставалось выбранным, не требуется В моем конкретном случае), это работает отлично. Я попытаюсь добавить упрощенный пример кода (может не компилироваться как есть, я вырвал несколько бит из моего рабочего кода и переименовал вещи перед вставкой, но, надеюсь, вы поймете эту идею) ниже.

Во-первых, активность списка (в моем случае), содержащая счетчик, назовем его MyListActivity:

 public class MyListActivity extends ListActivity { private Spinner mySpinner; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // TODO: other code as required... mySpinner = (Spinner) findViewById(R.id.mySpinner); mySpinner.setAdapter(new MySpinnerAdapter(this)); mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> aParentView, View aView, int aPosition, long anId) { if (aPosition == 0) { Log.d(getClass().getName(), "Ignoring selection of dummy list item..."); } else { Log.d(getClass().getName(), "Handling selection of actual list item..."); // TODO: insert code to handle selection resetSelection(); } } @Override public void onNothingSelected(AdapterView<?> anAdapterView) { // do nothing } }); } /** * Reset the filter spinner selection to 0 - which is ignored in * onItemSelected() - so that a subsequent selection of another item is * triggered, regardless of whether it's the same item that was selected * previously. */ protected void resetSelection() { Log.d(getClass().getName(), "Resetting selection to 0 (ie 'please select' item)."); mySpinner.setSelection(0); } } 

И код адаптера счетчика может выглядеть примерно так (на самом деле может быть внутренний класс в приведенном выше списке, если вы предпочитаете):

 public class MySpinnerAdapter extends BaseAdapter implements SpinnerAdapter { private List<MyListItem> items; // replace MyListItem with your model object type private Context context; public MySpinnerAdapter(Context aContext) { context = aContext; items = new ArrayList<MyListItem>(); items.add(null); // add first dummy item - selection of this will be ignored // TODO: add other items; } @Override public int getCount() { return items.size(); } @Override public Object getItem(int aPosition) { return items.get(aPosition); } @Override public long getItemId(int aPosition) { return aPosition; } @Override public View getView(int aPosition, View aView, ViewGroup aParent) { TextView text = new TextView(context); if (aPosition == 0) { text.setText("-- Please select --"); // text for first dummy item } else { text.setText(items.get(aPosition).toString()); // or use whatever model attribute you'd like displayed instead of toString() } return text; } } 

Я думаю, что (не пробовал это) такой же эффект мог быть достигнут с помощью setSelected(false) вместо setSelection(0) , но повторная настройка на «please select» подходит для моих целей. И, «смотри, Ма, не флаг!» (Хотя я думаю, что игнорирование 0 выборов не так уж и непохоже).

Надеюсь, это может помочь кому-то другому с аналогичным вариантом использования. 🙂 Для других случаев использования ответ Felix может быть более подходящим (спасибо Феликс!).

Посмотрите. Я не знаю, поможет ли это вам, но поскольку вы, похоже, устали искать ответ без особого успеха, эта идея может вам помочь, кто знает …

Класс Spinner получен из AbsSpinner . Внутри этого метода:

 void setSelectionInt(int position, boolean animate) { if (position != mOldSelectedPosition) { mBlockLayoutRequests = true; int delta = position - mSelectedPosition; setNextSelectedPositionInt(position); layout(delta, animate); mBlockLayoutRequests = false; } } 

Это AFAIK, взятый из 1.5 источника . Возможно, вы можете проверить этот источник, посмотреть, как работает Spinner / AbsSpinner, и, возможно, расширить этот класс, чтобы поймать правильный метод, а не проверить, есть ли position != mOldSelectedPosition .

Я имею в виду … это огромная «может быть» с большим количеством «ifs» (версия для Android стоит вспомнить и т. Д.), Но поскольку вы, похоже, разочарованы (и я был там с Android много раз), возможно, это может дать Вы немного «светлый». И я предполагаю, что нет других очевидных ответов, глядя на ваши предыдущие исследования.

Я желаю тебе удачи!

Изменение Spinner полезно, если вы хотите иметь несколько вариантов одновременно в одном и том же действии. Если вы хотите, чтобы у пользователя был иерархический выбор, например:

Что ты хочешь съесть?

Фрукты

  • яблоки
  • бананы
  • апельсины

Быстрое питание

  • бургеры
  • Fries
  • Хот-доги,

То ExpandableListView может быть лучше для вас. Он позволяет пользователю перемещаться по иерархии разных групп и выбирать дочерний элемент. Это будет похоже на то, что у вас есть несколько Spinners для выбора – если вы не хотите одновременного выбора, то есть.

Вот альтернативное решение для различения любых (предполагаемых или непреднамеренных) программных и инициированных пользователем изменений:

Создайте свой слушатель для счетчика как как OnTouchListener, так и OnItemSelectedListener

 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) { // Your selection handling code here userSelect = false; } } } 

Добавить слушателя в регистр счетчика для обоих типов событий

 SpinnerInteractionListener listener = new SpinnerInteractionListener(); mSpinnerView.setOnTouchListener(listener); mSpinnerView.setOnItemSelectedListener(listener); 

Это не будет обрабатывать случай, когда повторный выбор одного и того же элемента пользователем не вызывает метод onItemSelected (который я не наблюдал), но, я думаю, это может быть связано с добавлением некоторого кода в метод onTouch ,

Во всяком случае, проблемы, о которых говорил Амос, заставляли меня сходить с ума, прежде чем думать об этом решении, поэтому я думал, что поделюсь как можно шире. Есть много тем, которые обсуждают это, но я видел только одно другое решение, подобное этому: https://stackoverflow.com/a/25070696/4556980 .

Я работал над несколькими проблемами, упомянутыми в этом потоке, прежде чем я понял, что виджет PopupMenu – это то, что я действительно хотел. Это было легко реализовать без хаков и обходных решений, необходимых для изменения функциональности Spinner. PopupMenu был относительно новым, когда этот поток был запущен в 2011 году, но я надеюсь, что это поможет кому-то найти аналогичную функциональность.