Я хочу создать диалоговое окно выбора времени и даты, например, в приложении 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, очевидно, нашли способ, так что это можно сделать.