Установка счетчика onClickListener() в Android

Я пытаюсь заставить onClickListener запускать Spinner, но получаю следующую ошибку:

Java.lang.RuntimeException: «Не вызывайте setOnClickListener для AdapterView. Возможно, вместо этого вам нужен setOnItemClickListener»,

Я уверен, что хочу вызвать onClickListener, а НЕ onItemClickListener. Я нашел вопрос, заданный кем-то другим в Stack Overflow: Есть ли способ использовать setOnClickListener с Android Spinner?< /эм>

Ответ указан там:

Вам нужно будет установить прослушиватель кликов в базовом представлении (обычно это TextView с идентификатором: android.R.id.text1) счетчика. Для этого:

Создайте собственный счетчик. В конструкторе (с атрибутами) создайте счетчик, указав макет android.R.layout.simple_spinner_item. Сделайте findViewById(android.R.id.text1), чтобы получить TextView. Теперь установите onClickListener в TextView.

Я попробовал ответ, указанный там, но, похоже, он не работает. Я получаю нулевой указатель на TextView после выполнения findViewById().

Вот что я делаю:

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.layoutspinner,dataArray);

spinner.setAdapter(adapter);

TextView SpinnerText = (TextView)findViewById(R.id.spinnerText);
if (SpinnerText == null) {
    System.out.println("Not found");
}
else {
    SpinnerText.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            //Do something
        }
    });
}

Файл layoutspinner.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
                  android:id="@+id/spinnerText"
                  android:singleLine ="true"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
                  android:textSize="6pt"
                  android:gravity="right"/>

Что я делаю неправильно?

Я новичок в Stack Overflow, я не нашел способа опубликовать дополнительный вопрос в другой ветке (или прокомментировать, так как у меня мало представителей), поэтому я начал новый вопрос.

По рекомендации я попробовал это:

int a = spinnerMes.getCount();
int b = spinnerMes.getChildCount();
System.out.println("Count = " + a);
System.out.println("ChildCount = " + b);
for (int i = 0; i < b; i++) {
    View v = spinnerMes.getChildAt(i);
    if (v == null) {
        System.out.println("View not found");
    }
    else {
        v.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Click code
            }
        });
    }
}

Но LogCat не не показывает многообещающих результатов.

10-14 16:09:08.127: INFO/System.out(3116): Count = 7
10-14 16:09:08.127: INFO/System.out(3116): ChildCount = 0

Я тестировал это на уровнях API 7 и 8 с теми же результатами.


person blindstuff    schedule 13.10.2010    source источник


Ответы (7)


Следующее работает так, как вы этого хотите, но это не идеально.

public class Tester extends Activity {

    String[] vals = { "here", "are", "some", "values" };
    Spinner spinner;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        spinner = (Spinner) findViewById(R.id.spin);
        ArrayAdapter<String> ad = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, vals);
        spinner.setAdapter(ad);
        Log.i("", "" + spinner.getChildCount());
        Timer t = new Timer();
        t.schedule(new TimerTask() {

            @Override
            public void run() {
                int a = spinner.getCount();
                int b = spinner.getChildCount();
                System.out.println("Count =" + a);
                System.out.println("ChildCount =" + b);
                for (int i = 0; i < b; i++) {
                    View v = spinner.getChildAt(i);
                    if (v == null) {
                        System.out.println("View not found");
                    } else {
                        v.setOnClickListener(new View.OnClickListener() {

                            @Override
                            public void onClick(View v) {
                                        Log.i("","click");
                                        }
                        });
                    }
                }
            }
        }, 500);
    }
}

Дайте мне знать, как именно вам нужно, чтобы счетчик вел себя, и мы сможем найти лучшее решение.

person Dave.B    schedule 13.10.2010
comment
Я верю, что пробовал это сегодня безуспешно, но я сообщу, как только попробую еще раз, чтобы быть уверенным. - person blindstuff; 14.10.2010
comment
Я только что проверил код, я попробовал это, и я все еще получаю взамен нулевую ссылку. Любые идеи? - person blindstuff; 14.10.2010
comment
Отредактировал мой вопрос, еще не совсем там, но спасибо за помощь, я действительно потерялся здесь. - person blindstuff; 14.10.2010
comment
проблема с кодом, который я разместил, заключается в том, что счетчик фактически не получает никаких элементов до тех пор, пока экран не отобразится после выполнения onCreate. если вы переместите цикл в таймер, который срабатывает после рендеринга представления, он работает. однако проблема в том, что у счетчика всегда есть только 1 ребенок. когда вы выбираете счетчик, появляется диалоговое окно, чтобы вы могли выбрать значение. когда значение изменяется, создается новый дочерний элемент, и добавленное вами событие будет потеряно. Если бы вы могли сказать мне конкретно, как вам нужно, чтобы пиннер вел себя, мы могли бы придумать более элегантное решение. - person Dave.B; 14.10.2010
comment
Это работает, но проблема, которую вы описываете, является нарушителем условий сделки. Позвольте мне вернуться к проблеме, которая привела меня к необходимости этого. У меня есть экран с двумя счетчиками, как я уверен, вы знаете, что счетчики запускают onItemSelected при создании. Оба onItemSelected в этом действии запускают сетевой запрос, поэтому я решил использовать простой логический флаг, назовем его spinnerClicked. OnItemClickedListener проверяет, является ли spinnerClicked истинным, и выполняет выборку данных, в противном случае он просто игнорирует их. - person blindstuff; 14.10.2010
comment
Идея заключалась в том, чтобы установить onClick для счетчика, чтобы установить флаг в значение true, а после срабатывания onItemSelected установить для него значение false. Это позволяет не запускать 2 рабочих потока, а также предотвращает повторную загрузку данных при повороте экрана. Так что в основном я просто хотел, onClick, установить флаг в true. - person blindstuff; 14.10.2010
comment
почему бы просто не инициализировать логическое значение значением true, а затем установить его в значение false после первого щелчка? - person Dave.B; 14.10.2010
comment
Я хочу, чтобы он загружал данные, когда когда-либо выбирались новые параметры из любого счетчика, но чтобы он не срабатывал при вращении. Кнопка получения данных решила бы эту проблему, но это действительно последнее средство. - person blindstuff; 14.10.2010
comment
создайте словарь логических значений в oncreate со значением для каждого элемента в счетчике. в слушателе onitemSelect получите значение выбранного элемента, а затем проверьте словарь, чтобы увидеть, была ли загрузка завершена - person Dave.B; 14.10.2010
comment
Я сделал что-то похожее на словарь, и хотя решение далеко не элегантное, оно работает, спасибо Дейву за помощь. Я бы поднял это, но я все еще в паре очков от того, чтобы быть в состоянии. - person blindstuff; 15.10.2010
comment
Использование count() в качестве основы для индексации позволяет получить элементы, но они возвращаются в виде строк, поэтому вы не можете инструментировать щелчок. - person darthtrevino; 27.06.2011

Вот рабочее решение:

Вместо установки OnClickListener счетчика мы устанавливаем OnTouchListener и OnKeyListener.

spinner.setOnTouchListener(Spinner_OnTouch);
spinner.setOnKeyListener(Spinner_OnKey);

и слушатели:

private View.OnTouchListener Spinner_OnTouch = new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            doWhatYouWantHere();
        }
        return true;
    }
};
private static View.OnKeyListener Spinner_OnKey = new View.OnKeyListener() {
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            doWhatYouWantHere();
            return true;
        } else {
            return false;
        }
    }
};
person OferR    schedule 15.12.2011
comment
Когда я запустил этот код, я не смог получить доступ к выбранному элементу - он дал бы мне только ранее выбранный элемент??? Это случилось с вами? - person WaterBoy; 26.06.2012
comment
WaterBoy, такое поведение ожидаемо, поскольку эти обратные вызовы выполняются до того, как Android обработает события. Для моего приложения мне не нужен выбранный элемент, поэтому я не могу вам помочь. Прости. - person OferR; 26.06.2012
comment
Вы можете захотеть всегда возвращать false, если счетчик все равно должен отображать выпадающие элементы. - person Giulio Piancastelli; 11.07.2012
comment
Это все хорошо, но, регистрируя OnTouchListener, вы, кажется, теряете событие фокуса на Spinner, что означает, что вы не видите красивого подчеркивания и т. Д. Есть ли способ сохранить это, все еще применяя ваше решение? - person immichs; 23.07.2015

Всякий раз, когда вам нужно выполнить какое-либо действие по щелчку Spinner в Android, используйте следующий метод.

mspUserState.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            doWhatIsRequired();
        }
        return false;
    }
});

Одна вещь, о которой следует помнить, это всегда возвращать False при использовании вышеуказанного метода. Если вы вернете True, то элементы раскрывающегося списка счетчика не будут отображаться при нажатии счетчика.

person Gaurav Arora    schedule 04.10.2013
comment
Я понимаю, что вы говорите. Тем не менее, если вы пытаетесь, например, отобразить диалоговое окно предупреждения вместо элементов раскрывающегося списка, вы должны вернуть true - person Maxime Claude; 08.03.2017

Лично я использую это:

    final Spinner spinner = (Spinner) (view.findViewById(R.id.userList));
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {                

            userSelectedIndex = position;
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });  
person Lumi    schedule 02.04.2014

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

Вы можете использовать setOnItemSelectedListener:

Spinner s1;
s1 = (Spinner)findViewById(R.id.s1);
int selectionCurrent = s1.getSelectedItemPosition();

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            if (selectionCurrent != position){
                // Your code here
            }
            selectionCurrent= position;
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // Your code here
    }
});
person sumit pandey    schedule 25.09.2012

Я предлагаю разделить все события для Spinner на два типа:

  1. Пользовательские события (вы имели в виду событие «клик»).

  2. Программные события.

Я также предлагаю, чтобы, когда вы хотите поймать пользовательское событие, вы просто хотели избавиться от «событий программы». Итак, это довольно просто:

private void setSelectionWithoutDispatch(Spinner spinner, int position) {
    AdapterView.OnItemSelectedListener onItemSelectedListener = spinner.getOnItemSelectedListener();
    spinner.setOnItemSelectedListener(null);
    spinner.setSelection(position, false);
    spinner.setOnItemSelectedListener(onItemSelectedListener);
}

Есть ключевой момент: вам нужен setSelection(position, false). «false» в параметре анимации немедленно вызовет событие. По умолчанию событие помещается в очередь событий.

person Slava    schedule 15.02.2015

Класс Spinner реализует DialogInterface.OnClickListener, тем самым эффективно перехватывая стандартный View.OnClickListener.

Если вы не используете Spinner подкласса или не собираетесь это делать, выберите другой ответ.

В противном случае просто добавьте следующий код в свой собственный Spinner:

@Override
/** Override triggered on 'tap' of closed Spinner */
public boolean performClick() {
    // [ Do anything you like here ]
    return super.performClick();
}

Пример: отображать предварительно заданную подсказку через Snackbar при каждом открытии Spinner:

private String sbMsg=null;      // Message seen by user when Spinner is opened.
public void setSnackbarMessage(String msg) { sbMsg=msg; }
@Override
/** Override triggered on 'tap' of closed Spinner */
public boolean performClick() {
    if (sbMsg!=null && !sbMsg.isEmpty()) { /* issue Snackbar */ }
    return super.performClick();
}

Захват щелчка закрытого Spinner

Пользовательский Spinner — отличная отправная точка для программной стандартизации внешнего вида Spinner в вашем проекте.

Если интересно, посмотрите здесь

person Bad Loser    schedule 30.10.2018