OnItemClickListener для элемента счетчика, проблема с setOnItemSelectedListener

Я хочу создать диалоговое окно выбора времени и даты, например, в приложении Google Keep, которое отображается, когда нужно напомнить о событии в будущем.

В диалоговом окне есть два вращающихся поля для даты и времени суток. Первые несколько полей — это словесные описания, такие как «Сегодня», «Завтра» и т. д. Последний элемент — это ручной выбор даты. При нажатии на нее открывается окно выбора времени/даты.

Диалог выбора даты и времени

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

В моем примере TimeSelection реализованы методы getView и getDropDownView. Метод getDropDownView не интересен, он устанавливает значения, которые будут отображаться в элементах счетчика, как обычно в этой ситуации.

@Override
    public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        ViewHolderDropDown holder;
        TimeSelectionModel model = getItem(position);
        if (convertView == null) {
            holder = new ViewHolderDropDown();
            convertView = inflater.inflate(R.layout.time_spinner_drop_down_item, parent, false);
            holder.verbalTimeTextView = (TextView) convertView.findViewById(R.id.verbal_time_text_view);
            holder.timeTextView = (TextView) convertView.findViewById(R.id.time_text_view);
            convertView.setTag(R.layout.time_spinner_drop_down_item, holder);
        } else {
            holder = (ViewHolderDropDown) convertView.getTag(R.layout.time_spinner_drop_down_item);
        }

        holder.timeTextView.setText(model.time);
        holder.verbalTimeTextView.setText(model.verbalTime);

        return convertView;
    }

Единственная нестандартность в том, что он заполняет два TextView для словесного описания Утро, Вечер и т.д. и точное 8:00.

Метод getView отличается тем, что вместо заполнения своих элементов с помощью обычного массива данных он берет значение из поля selectedTime. Через мгновение я вернусь к тому, как установлено это поле.

@NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.time_spinner_item, parent, false);
            holder.timeTextView = (TextView) convertView.findViewById(R.id.time_text_view);
            convertView.setTag(R.layout.time_spinner_item, holder);
        } else {
            holder = (ViewHolder) convertView.getTag(R.layout.time_spinner_item);
        }

        holder.timeTextView.setText(selectedTime);

        return convertView;
    }

DateTimeSelectionDialog, который содержит оба этих представления, реализует setOnItemSelectedListener для обоих этих счетчиков, которые снова аналогичны.

timeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        Log.d(TAG, "onItemSelected");
        if (position == POSITION_MORNING) {
            timeAdpater.setTime(8, 0);
        } else if (position == POSITION_AFTERNOON) {
            timeAdpater.setTime(13, 0);
        } else if (position == POSITION_EVENING) {
            timeAdpater.setTime(18, 0);
        } else if (position == POSITION_NIGHT) {
            timeAdpater.setTime(20, 0);
        } else {
            dateTimeDialogCallbacks.selectTimeManually();
        }
    }

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

    }
});

Именно здесь я установил метку. Единственным исключением является последнее поле, где я называю dateTimeDialogCallbacks.selectTimeManually(); реализованным нижестоящим действием. После выбора времени из TimePicker я вызываю этот метод, реализованный в DateTimeSelectionDialog.

public void setTime(int hour, int minute) {
        this.hour = hour;
        this.minute = minute;
        timeAdpater.setTime(hour, minute);
    }

timeAdapter.setTime(hour, minute) установит поле и уведомит адаптер об изменении данных.

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

Итак, мой вопрос: каков обходной путь для этого? Люди в google, очевидно, нашли способ, так что это можно сделать.


person Lukasz    schedule 15.11.2017    source источник
comment
Попробуйте эту ссылку. Надеюсь, поможет.   -  person Cagri Yalcin    schedule 15.11.2017
comment
@CagriYalcin Отличные вещи. Только пришлось изменить его, чтобы переопределить AppComapatSpiner.   -  person Lukasz    schedule 15.11.2017


Ответы (1)


Что ж, в контексте вашего кода вы можете добавить проверки в onNothingSelected (родительский элемент AdapterView), что не является идеальным, но обходным путем!

person Sara Tirmizi    schedule 15.11.2017
comment
Я не совсем понимаю. onNothingSelected вызывается, когда выделение исчезает из представления. Чем это полезно для меня? Я не вижу, где это будет называться. - person Lukasz; 15.11.2017
comment
Извините, мой плохой, я скучаю по вашему вопросу. - person Sara Tirmizi; 16.11.2017