0

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.

A date and time selection dialog

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.

Lukasz
  • 2,257
  • 3
  • 26
  • 44

1 Answers1

0

Well , within the context of your code, you can add checks in onNothingSelected(AdapterView parent) which is not ideal but a workaround!

Sara Tirmizi
  • 417
  • 4
  • 10
  • I don't quite follow. `onNothingSelected` is called when the selection disappears from a view. How is this useful for me? I don't see where this would be called. – Lukasz Nov 15 '17 at 12:47
  • Sorry my bad, I miss understood your question. – Sara Tirmizi Nov 16 '17 at 04:00