26

我正在寻找一种方法来设置 Android 上可选择的最大和TimePickerDialog最小时间,并将默认分钟间隔从 1 分钟更改为 5 分钟,

我以为这很容易,但我找不到方法!

4

9 回答 9

38

这个答案已经过时了

它不适用于 Android 5 或更高版本。


这是提琴手答案的扩展。在某些 Android 版本中,TimePickerDialog 以某种方式未设置 onTimeChangedListener:

前任。 http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.1_r1.2/android/app/TimePickerDialog.java

因此永远不会调用 onTimeChanged 方法!目前针对此问题的最佳解决方案可能是使用 fiddler 的最小/最大逻辑编写自定义 TimePickerDialog。

更丑陋的解决方法是这个。(使用反射添加侦听器)我还更新了标题以显示当前选择的时间。

package com.mysuger.android.dialogs;

import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.Calendar;

import android.app.TimePickerDialog;
import android.content.Context;
import android.widget.TimePicker;

/**
 * A time dialog that allows setting a min and max time.
 * 
 */
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) {

    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);
}
 }
于 2013-06-05T14:29:20.617 回答
14

对于棒棒糖和更高版本的android,您可以使用这个修改后的 RangeTimePickerDialog 类

(在棒棒糖中,Timepicker 默认使用时钟模式(材料设计),因此旧的自定义类将无法工作。我们可以将模式更改为微调器以获取最新版本,并可以重用该类)

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, int dialogTheme, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
        super(context, callBack, hourOfDay, minute, is24HourView);
        currentHour = hourOfDay;
        currentMinute = minute;
        dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
        fixSpinner(context, hourOfDay, minute, is24HourView);

        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) {

        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);
    }


    private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // android:timePickerMode spinner and clock began in Lollipop
            try {
                // Get the theme's android:timePickerMode
                //two modes are available clock mode and spinner mode ... selecting spinner mode for latest versions
                final int MODE_SPINNER = 2;
                Class<?> styleableClass = Class.forName("com.android.internal.R$styleable");
                Field timePickerStyleableField = styleableClass.getField("TimePicker");
                int[] timePickerStyleable = (int[]) timePickerStyleableField.get(null);
                final TypedArray a = context.obtainStyledAttributes(null, timePickerStyleable, android.R.attr.timePickerStyle, 0);
                Field timePickerModeStyleableField = styleableClass.getField("TimePicker_timePickerMode");
                int timePickerModeStyleable = timePickerModeStyleableField.getInt(null);
                final int mode = a.getInt(timePickerModeStyleable, MODE_SPINNER);
                a.recycle();
                if (mode == MODE_SPINNER) {
                    TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this);
                    Class<?> delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate");
                    Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate");
                    Object delegate = delegateField.get(timePicker);
                    Class<?> spinnerDelegateClass;
                    if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP) {
                        spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate");
                    } else {

                        spinnerDelegateClass = Class.forName("android.widget.TimePickerClockDelegate");
                    }
                    if (delegate.getClass() != spinnerDelegateClass) {
                        delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate!
                        timePicker.removeAllViews(); // remove the TimePickerClockDelegate views
                        Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class);
                        spinnerDelegateConstructor.setAccessible(true);
                        // Instantiate a TimePickerSpinnerDelegate
                        delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0);
                        delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate
                        // Set up the TimePicker again, with the TimePickerSpinnerDelegate
                        timePicker.setIs24HourView(is24HourView);
                        timePicker.setCurrentHour(hourOfDay);
                        timePicker.setCurrentMinute(minute);
                        timePicker.setOnTimeChangedListener(this);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    private static Field findField(Class objectClass, Class fieldClass, String expectedName) {
        try {
            Field field = objectClass.getDeclaredField(expectedName);
            field.setAccessible(true);
            return field;
        } catch (NoSuchFieldException e) {} // ignore
        // search for it if it wasn't found under the expected ivar name
        for (Field searchField : objectClass.getDeclaredFields()) {
            if (searchField.getType() == fieldClass) {
                searchField.setAccessible(true);
                return searchField;
            }
        }
        return null;
    }
}
于 2018-02-19T07:33:44.173 回答
8

您可以以此为起点。

我扩展了 TimePickerDialog 并添加了 2 个方法setMinsetMax.

在该onTimeChanged方法中,我检查新时间对于最小/最大时间是否有效。

不过还是需要打磨一下。。。

public class BoundTimePickerDialog extends TimePickerDialog {

    private int minHour = -1, minMinute = -1, maxHour = 100, maxMinute = 100;

    private int currentHour, currentMinute;

    public BoundTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
        super(context, callBack, hourOfDay, minute, is24HourView);
    }

    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) {
        super.onTimeChanged(view, hourOfDay, minute);

        boolean validTime;
        if(hourOfDay < minHour) {
            validTime = false;
        }
        else if(hourOfDay == minHour) {
            validTime = minute >= minMinute;
        }
        else if(hourOfDay == maxHour) {
            validTime = minute <= maxMinute;
        }
        else {
            validTime = true;
        }

        if(validTime) {
            currentHour = hourOfDay;
            currentMinute = minute;
        }
        else {
            updateTime(currentHour, currentMinute);
        }
    }
}
于 2012-11-22T16:15:48.183 回答
4

重构提琴手的代码后:

public class RangeTimePickerDialog extends TimePickerDialog {

    private int mMinHour = -1;
    private int mMinMinute = -1;
    private int mMaxHour = 100;
    private int mMaxMinute = 100;
    private int mCurrentHour;
    private int mCurrentMinute;

    public RangeTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, 
        int minute, boolean is24HourView) {
        super(context, callBack, hourOfDay, minute, is24HourView);
        mCurrentHour = hourOfDay;
        mCurrentMinute = minute;
        // Somehow the onTimeChangedListener is not set by TimePickerDialog
        // in some Android Versions, so, Adding the listener using
        // reflections
        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) {
        mMinHour = hour;
        mMinMinute = minute;
    }

    public void setMax(int hour, int minute) {
        mMaxHour = hour;
        mMaxMinute = minute;
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        super.onTimeChanged(view, hourOfDay, minute);
        boolean validTime;
        if (((hourOfDay < mMinHour ) || (hourOfDay == mMinHour && minute < mMinMinute)) 
                || ((hourOfDay > mMaxHour) || (hourOfDay == mMaxHour && minute > mMaxMinute))) {
            validTime = false;
        } else {
            validTime = true;
        }
        if (validTime) {
            mCurrentHour = hourOfDay;
            mCurrentMinute = minute;
        } else {
            updateTime(mCurrentHour, mCurrentMinute);
        }
    }
}
于 2014-10-13T15:09:10.330 回答
2

没有设置最大/最小时间的本机方法,但如果您扩展它可能会起作用,onTimeChanged或者updateTime您可以防止将时间设置为超出范围的值。

于 2012-11-22T16:12:22.533 回答
2

您可以只使用带有反射的自定义 TimePicker 来设置值。

 @Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();

    try {
        Class<?> classForid = Class.forName("com.android.internal.R$id");
        Field field = classForid.getField("minute");

        NumberPicker mMinuteSpinner = (NumberPicker) findViewById(field.getInt(null));
        mMinuteSpinner.setMinValue(5);
        mMinuteSpinner.setMaxValue((60 / timeInterval) - 1);

        List<String> displayedValues = new ArrayList<>();
        for (int i = 0; i < 60; i += timeInterval)
            displayedValues.add(String.format("%02d", i));
        mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));

        mMinuteSpinner.setWrapSelectorWheel(true);

    } catch (Exception e) {
        e.printStackTrace();
    }

}

所以你可以设置你想要的值

于 2016-05-18T03:02:47.283 回答
0

希望这会有所帮助。我使用了 Joda 时间库。

public class RangeTimePicker extends TimePicker implements
        TimePicker.OnTimeChangedListener {

    private int mMinHour = -1;

    private int mMinMinute = -1;

    private int mMaxHour = 25;

    private int mMaxMinute = 61;

    private int mCurrentHour;

    private int mCurrentMinute;


    public RangeTimePicker(Context context) {
        super(context);
        setOnTimeChangedListener(this);
    }

    public RangeTimePicker(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnTimeChangedListener(this);
    }

    public RangeTimePicker(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setOnTimeChangedListener(this);
    }

    public void setMaxTime(int hourIn24, int minute) {
        mMaxHour = hourIn24;
        mMaxMinute = minute;

        LocalTime currentTime = LocalTime.now();
        LocalTime maxTime = new LocalTime(mMaxHour, mMaxMinute);

        if (currentTime.isAfter(maxTime)) {
            this.setCurrentHour(mCurrentHour = currentTime.getHourOfDay());
            this.setCurrentMinute(
                    mCurrentMinute = currentTime.getMinuteOfHour());
        }

    }

    public void setMinTime(int hourIn24, int minute) {
        mMinHour = hourIn24;
        mMinMinute = minute;

        LocalTime currentTime = LocalTime.now();
        LocalTime minTime = new LocalTime(mMinHour, mMinMinute);

        if (currentTime.isBefore(minTime)) {
            this.setCurrentHour(mCurrentHour = minTime.getHourOfDay());
            this.setCurrentMinute(mCurrentMinute = minTime.getMinuteOfHour());
        }
    }


    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        boolean validTime = true;
        if (hourOfDay < mMinHour || (hourOfDay == mMinHour
                && minute < mMinMinute)) {
            validTime = false;
        }

        if (hourOfDay > mMaxHour || (hourOfDay == mMaxHour
                && minute > mMaxMinute)) {
            validTime = false;
        }

        if (validTime) {
            mCurrentHour = hourOfDay;
            mCurrentMinute = minute;
        }

        setCurrentHour(mCurrentHour);
        setCurrentMinute(mCurrentMinute);

    }
}
于 2015-05-21T07:53:11.883 回答
0

希望这项工作,它与我完美配合......

设置时间选择器的最长时间。

        timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
        @Override
        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {

            if (!mIsOnTimeChanged) {
                mIsOnTimeChanged = true;

                Calendar c = Calendar.getInstance();

                //get the selected day if it is before today allow AM and PM trick
                //else apply rules


                int selected_year = datePicker.getYear();
                int selected_month = datePicker.getMonth();
                int selected_day = datePicker.getDayOfMonth();


                int today = c.get(Calendar.DAY_OF_MONTH);
                int year = c.get(Calendar.YEAR);
                int month = c.get(Calendar.MONTH);


                int hour = c.get(Calendar.HOUR);
                hour += 12;
                int min = c.get(Calendar.MINUTE);

                //Check if user enter hh | mm | more than current reset the timePicker with the current time

                //http://stackoverflow.com/questions/2659954/timepickerdialog-and-am-or-pm

                if ((hourOfDay == hour | hour < hourOfDay | hourOfDay > hour | hour > hourOfDay | minute > min) && (selected_month == month && selected_day == today && selected_year == year)) {

                    int AM_PM_Value = hourOfDay;

                    Calendar datetime = Calendar.getInstance();

                    int hour_without_24 = (hour - 12);
                    if ((datetime.get(Calendar.AM_PM) == Calendar.AM) && (hourOfDay > hour_without_24)) {
                        //set AM
                        timePicker.setCurrentHour(hour - 12);
                    }

                    if (hourOfDay == (hour - 12) && minute > min) {
                        timePicker.setCurrentMinute(min);

                    }

                    if (hourOfDay > hour && datetime.get(Calendar.AM_PM) != Calendar.AM) {
                        timePicker.setCurrentHour(hour);

                        if (minute > min) {
                            timePicker.setCurrentMinute(min);

                        }
                    }


                } else if (selected_month != month | selected_day != today | selected_year != year) {

                } else if (hourOfDay == hour && minute > min) {
                    timePicker.setCurrentMinute(min);
                } else if (hourOfDay > hour) {
                    timePicker.setCurrentHour(hour);

                    if (minute > min) {
                        timePicker.setCurrentMinute(min);

                    }
                }
                //
                isTimePickerChanged = true;
                String AM_PM;
                if (hourOfDay < 12) {
                    AM_PM = "AM";
                } else {
                    AM_PM = "PM";
                }

                //to set as 12 hour
                time_format = (hourOfDay + ":" + minute + ":" + "00");

                if (hourOfDay > 12) {
                    hourOfDay = (hourOfDay - 12);
                }

                st_time = (hourOfDay + ":" + pad(minute) + " " + AM_PM);

                mIsOnTimeChanged = false;

            }


        }
    });
于 2016-02-19T23:31:19.847 回答
-1

我以@Zarooka 的解决方案为起点。我想我发现了一个错误。如果您的开始时间已经超出范围,那么您将无法再移动它,因为任何“onChanged”都被拒绝。这就是为什么我扩展了 setMax 和 setMin 以便在设置最小值/最大值时进入有效范围。

package de.appdream.garooda.view;

import java.util.Calendar;
import java.util.Date;

import android.app.TimePickerDialog;
import android.content.Context;
import android.text.format.DateFormat;
import android.widget.TimePicker;

import java.lang.reflect.Field; 


public class GaroodaTimePickerDialog extends TimePickerDialog {

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

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

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

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

public GaroodaTimePickerDialog(Context context, OnTimeSetListener callBack, int hour, int minute,
        boolean is24HourView) {
    super(context, callBack, hour, minute, is24HourView);

    currentHour = hour;
    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;

    Calendar min = Calendar.getInstance();
    Calendar existing = Calendar.getInstance();

    min.set(Calendar.HOUR_OF_DAY, minHour);
    min.set(Calendar.MINUTE, minMinute);

    existing.set(Calendar.HOUR_OF_DAY, currentHour);
    existing.set(Calendar.MINUTE, currentMinute);

    if (existing.before(min)) {
        currentHour = minHour;
        currentMinute = minMinute;
        updateTime(currentHour, currentMinute);
    }
}

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

    Calendar max = Calendar.getInstance();
    Calendar existing = Calendar.getInstance();

    max.set(Calendar.HOUR_OF_DAY, maxHour);
    max.set(Calendar.MINUTE, maxMinute);

    existing.set(Calendar.HOUR_OF_DAY, currentHour);
    existing.set(Calendar.MINUTE, currentMinute);

    if (existing.after(max)) {
        currentHour = maxHour;
        currentMinute = maxMinute;
        updateTime(currentHour, currentMinute);
    }

}

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

    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);
}
}
于 2014-06-17T09:29:07.280 回答