I want to create a time and date selection dialog, like the one in the goolgle keep app, shown when one wants to be reminded about an event in the future.
The dialog has two spinner fields for the date and the time of day. The first few fields are verbal descriptions like Today, Tomorrow etc. The last element is a manual selection of the date. Clicking it opens a Time/Date picker.
My current solution uses two custom adapter for each of these Spinners. The adapters are analogous so I will further only describe the time selection part.
My TimeSelection example implements both the getView
and getDropDownView
methods. The getDropDownView
method isn't interesting it set the values to be displayed in the spinner items as you usually would in this situation.
@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;
}
The only non standard thing is that it populates two TextViews for a verbal description Morning, Evening etc. and an exact one 8:00.
The getView
method is different instead of populating its members by usig the regular data array it takes the value from a field selectedTime
. In a moment I will come back to how this field is set.
@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;
}
The DateTimeSelectionDialog
which holds both these views implements a setOnItemSelectedListener
for both these spinners which are again analogous.
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) {
}
});
It is here where I set the label. The one exception is the last field where I call dateTimeDialogCallbacks.selectTimeManually();
implemented by the underling activity. After selecting the time from a TimePicker I call this method implemented by the DateTimeSelectionDialog.
public void setTime(int hour, int minute) {
this.hour = hour;
this.minute = minute;
timeAdpater.setTime(hour, minute);
}
timeAdapter.setTime(hour, minute)
will set the field and notify the adapter about a data change.
Everything seemed to be working great.
The problem is setOnItemSelectedListener
isn't really the same thing like a normal click listener. Because it will only be called if the clicked field is different than the previously selected one.
So once the user selects the time manually he can't select it a second time manually. This is of course a bug.
So my question is what is the workaround for this? The people at google obviously found a way, so it can be done.