Запретить пользователю выбирать прошедшее время — TimePickerDialog

ВАЖНОЕ РЕДАКТИРОВАНИЕ: я немного поискал, и кажется, что OnTimeChangedListener не срабатывает в Android 5.0 (API 21). Ответ Густаво ниже будет работать для API 20 или ниже и API 22, который я тестировал. (Источник)

Я хотел бы запретить пользователю вводить время до текущего времени. Я проверяю действительное время, используя метод before, предоставленный Date. Как я могу предотвратить принятие диалогом недопустимого времени в рамках этой проверки достоверности?

Я опустил лишний код, где я инициализирую выбранное время (как Date).

final Calendar mcurrentTime = Calendar.getInstance();
final int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
final int minute = mcurrentTime.get(Calendar.MINUTE);
final TimePickerDialog mTimePicker;
mTimePicker = new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() {
    @Override
    public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {

        //PSEUDO: Date selectedDateTime init here

        if (selectedDateTime.before(mcurrentTime.getTime())) {
            // prevent user from selecting time
        }
    }
}, hour, minute, true);//true = 24 hour time
mTimePicker.setTitle("Select Time");
mTimePicker.show(); 

person McGuile    schedule 07.07.2015    source источник
comment
Проверьте ответ на этот пост.   -  person Gustavo Morales    schedule 07.07.2015
comment
Кажется, я уже сделал это, но безуспешно: gist.github.com/mcguile/7cfc107bba3772228d26 .   -  person McGuile    schedule 07.07.2015
comment
Проверяйте значения в методе onTimeChanged. Сравните это со своими ценностями.   -  person Gustavo Morales    schedule 07.07.2015
comment
Можете ли вы добавить ответ с вашим кодом? Было бы намного проще следовать вашему коду. Примет ответ в случае успеха.   -  person McGuile    schedule 07.07.2015
comment
Проверьте свое время в средстве выбора, вы можете прокручивать значения внутри, но время сверху не меняется. Проверьте, например, с помощью mTimePicker.setMin(9, 00) и mTimePicker.setMax(18, 00).   -  person Gustavo Morales    schedule 07.07.2015


Ответы (2)


Здесь исходный пост.

После ответа вы должны добавить класс TimePickerDialog.

public class RangeTimePickerDialog extends TimePickerDialog {

private int minHour = -1;
private int minMinute = -1;

private int maxHour = 25;
private int maxMinute = 25;

private int currentHour = 0;
private int currentMinute = 0;

private Calendar calendar = Calendar.getInstance();
private DateFormat dateFormat;


public RangeTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
    super(context, callBack, hourOfDay, minute, is24HourView);
    currentHour = hourOfDay;
    currentMinute = minute;
    dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);

    try {
        Class<?> superclass = getClass().getSuperclass();
        Field mTimePickerField = superclass.getDeclaredField("mTimePicker");
        mTimePickerField.setAccessible(true);
        TimePicker mTimePicker = (TimePicker) mTimePickerField.get(this);
        mTimePicker.setOnTimeChangedListener(this);
    } catch (NoSuchFieldException e) {
    } catch (IllegalArgumentException e) {
    } catch (IllegalAccessException e) {
    }
}

public void setMin(int hour, int minute) {
    minHour = hour;
    minMinute = minute;
}

public void setMax(int hour, int minute) {
    maxHour = hour;
    maxMinute = minute;
}

@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {

    Log.d("DADADADA", "onTimeChanged");

    boolean validTime = true;
    if (hourOfDay < minHour || (hourOfDay == minHour && minute < minMinute)) {
        validTime = false;
    }

    if (hourOfDay > maxHour || (hourOfDay == maxHour && minute > maxMinute)) {
        validTime = false;
    }

    if (validTime) {
        currentHour = hourOfDay;
        currentMinute = minute;
    }

    updateTime(currentHour, currentMinute);
    updateDialogTitle(view, currentHour, currentMinute);
}

private void updateDialogTitle(TimePicker timePicker, int hourOfDay, int minute) {
    calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
    calendar.set(Calendar.MINUTE, minute);
    String title = dateFormat.format(calendar.getTime());
    setTitle(title);
}
}

После этого замените свой TimePickerDialog на RangeTimePickerDialog.

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final Calendar mcurrentTime = Calendar.getInstance();
    final int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
    final int minute = mcurrentTime.get(Calendar.MINUTE);
    final RangeTimePickerDialog mTimePicker;
    mTimePicker = new RangeTimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {

            Log.d("TAG", "inside OnTimeSetListener");

        }
    }, hour, minute, true);//true = 24 hour time
    mTimePicker.setTitle("Select Time");
    mTimePicker.setMin(hour, minute);
    mTimePicker.show();
}
}

После этого проверьте свой диалог, время не выходит за пределы, я проверил это как с помощью setMax(), так и с setMin(), а также установил только один.

person Gustavo Morales    schedule 07.07.2015
comment
Это точный код, который у меня есть. Название не меняется, чтобы показать выбранное время, как вы предлагаете, и не ограничивает время, которое вы можете выбрать. Чего-то не хватает. - person McGuile; 07.07.2015
comment
Очистите свой проект и запустите его снова. Мой код работает на телефоне. Android SDK 14 или выше. - person Gustavo Morales; 07.07.2015
comment
Извините, я сделал это и никаких изменений. Мой код точно соответствует вашему. Я не понимаю, почему это работает для вас, а не для меня. Это позволяет мне выбрать любое время, и время меняется на выбранное время. Я на API 21. - person McGuile; 07.07.2015
comment
Проверьте мое последнее редактирование, так выглядит мой код, а activity_main.xml в активности пусто, без каких-либо компонентов. - person Gustavo Morales; 07.07.2015
comment
Я даже протестировал его в пустой MainActivity и все тот же результат: можно выбрать все времена. - person McGuile; 07.07.2015
comment
Я протестировал ваш код, заменив мой, и у меня он отлично работает. В самсунг S4. - person Gustavo Morales; 07.07.2015
comment
Ну тогда я сбит с толку. Спасибо за ваше время, даже если оно не было успешным. Возможно, дело в API. Проголосовал. - person McGuile; 07.07.2015
comment
Хороший ответ. За исключением использования отражения. Нормальный интерфейс был бы намного лучше. +1 тем не менее - person Chad Bingham; 07.07.2015
comment
@Gustavo - вам действительно нужно приписать это человеку, который изначально написал ответ. Ознакомьтесь с Политикой атрибуции StackOverflows. - person Chad Bingham; 07.07.2015
comment
@LoyalRayne Да, как мне это сделать? В моем первом комментарии к этому сообщению я отсылаю пользователя к исходному сообщению. - person Gustavo Morales; 07.07.2015
comment
Просто опубликуйте ссылку на оригинальный ответ. Вот и все ;) ура - person Chad Bingham; 07.07.2015
comment
@Gustavo Я заметил, что onTimeChanged() никогда не вызывается. Это вызвано для вас? - person McGuile; 07.07.2015
comment
Да, он вызывается, поместите сообщение LOG в метод onTimeChanged() и проверьте, вызывается ли он для вас. Я также заметил, что решения нет в LG G3 с API 21, но оно работает с API 19 в Samsung S4. Я думаю, что виджеты имеют разное поведение. - person Gustavo Morales; 07.07.2015
comment
Сообщение отредактировано. Очень странно, что это не работало на API 21, но работает на 22 и 20 или ниже. - person McGuile; 07.07.2015
comment
Этот код не работает на леденце, работает только на устройстве до леденца. - person akhil batlawala; 08.07.2016
comment
Пожалуйста, дайте лучшее решение - person akhil batlawala; 08.07.2016

Метод onTimeSet() вызывается один раз при закрытии диалогового окна и дважды при нажатии кнопки «Готово».

Я бы просто проверил в этом методе при втором вызове. Игнорировать первое. Если он недействителен, покажите ошибку (возможно, тост) и снова покажите диалоговое окно.

Разрабатывать

Оба вызова onTimeSet будут одинаковыми по времени. Теперь у меня нет ссылки, но я полагаю, что один вызов - это когда диалоговое окно было показано (установлено время или нет), а затем было отменено. Два — именно так, но вместо отмены это происходит, когда пользователь нажимает «Готово».

Причина, по которой я говорю игнорировать первый, заключается в том, что он может установить время и принять решение об отмене. В таком случае не берите этот onTimeSet(). Если для вас это не имеет значения, то не стоит об этом беспокоиться.

person Chad Bingham    schedule 07.07.2015
comment
Я не знал, что он onTimeSet() вызывается дважды. Не могли бы вы уточнить, как отличить 1-й звонок от 2-го звонка? - person McGuile; 07.07.2015
comment
Вы знаете, как проигнорировать первый звонок? Или даже узнать, первый это звонок или второй? - person McGuile; 07.07.2015
comment
Много способов. Вот где вы должны придумать алгоритм, который будет работать. Я бы, вероятно, использовал и int. Установите его на 0, когда вы показываете диалог. Затем, когда вы получите dateSet, проверьте int. Если это 0, добавить один/игнорировать дату. если 1, обрабатывать дату. (тогда, чтобы быть в безопасности. Установите int снова на 0). Что-то такое. - person Chad Bingham; 07.07.2015
comment
А, ладно, я мог подумать об этом. Я просто предположил, что вы имели в виду, что для этого есть определенные методы. - person McGuile; 07.07.2015