Android日期选择器最小和最大日期在API级别11之前

21

我正在尝试在 Android 上设置日期选择器的最小和最大日期,适用于 API 级别 11 之前。我使用了以下代码:

mDatePickerField = startDatePickerDialog.getClass().getDeclaredField("mDatePicker");
mDatePickerField.setAccessible(true);

DatePicker startDatePickerInstance =(DatePicker)mDatePickerField.get(startDatePickerDialog);
startDatePickerInstance.init(mYearMin, mMonthMin, mDayMin, new DatePicker.OnDateChangedListener() {
    @Override
    public void onDateChanged(DatePicker datePicker, int i, int i1, int i2) {
        Date maxDate = new Date(mYearMax, mMonthMax, mDayMax, 0, 0, 0);
        Date selectedDate = new Date(i, i1, i2, 0, 0, 0);
        if (selectedDate.after(maxDate)) {
            datePicker.updateDate(mYearMax, mMonthMax, mDayMax);                                        
        }
    }
}

然而,updateDate方法会再次触发 onDateChanged 事件,导致日期选择器没有更新。
有人能帮忙解决这个问题吗?

7个回答

38

您可以使用init datePicker方法设置范围。 例如,设置最小值:

// Calendar
this.calendar = new GregorianCalendar();
this.datePicker = (DatePicker) findViewById(R.id.xxxxx);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    // (picker is a DatePicker)
    this.datePicker.setMinDate(this.calendar.getTimeInMillis());
} else {
    final int minYear = this.calendar.get(Calendar.YEAR);
    final int minMonth = this.calendar.get(Calendar.MONTH);
    final int minDay = this.calendar.get(Calendar.DAY_OF_MONTH);

    this.datePicker.init(minYear, minMonth, minDay,
            new OnDateChangedListener() {

                public void onDateChanged(DatePicker view, int year,
                        int month, int day) {
                    Calendar newDate = Calendar.getInstance();
                    newDate.set(year, month, day);

                    if (calendar.after(newDate)) {
                        view.init(minYear, minMonth, minDay, this);
                    }
                }
            });
    Log.w(TAG, "API Level < 11 so not restricting date range...");
}

3
newDate.after(calendar) for setting MAX Date and calendar.after(newDate) for setting MIN Date - DeltaCap019
1
你有没有想过如何同时使用MIN和MAX,使用这种方法似乎无法实现。 - Ionut Negru
你也可以使用反射来获取字段 https://dev59.com/iWPVa4cB1Zd3GeqP7Z0z - Gelldur

7
这个DatePicker自定义类允许我们指定最大和最小日期。
public class DatePickerDialogWithMaxMinRange extends DatePickerDialog {

 static int maxYear=2005; 
 static int maxMonth=11;
 static int maxDay=31;

 int minYear=1955;
 int minMonth=0;
 int minDay=1;


public DatePickerDialogWithMaxMinRange(Context context,  OnDateSetListener callBack,int minYear,int minMonth,int minDay,int maxYear,int maxMonth,int maxDay) {
    super(context,callBack, maxYear, maxMonth, maxDay);
    this.minDay = minDay;
    this.minMonth = minMonth;
    this.minYear = minYear;
    DatePickerDialogWithMaxMinRange.maxDay = maxDay;
    DatePickerDialogWithMaxMinRange.maxMonth = maxMonth;
    DatePickerDialogWithMaxMinRange.maxYear = maxYear;
}

@Override
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
    super.onDateChanged(view, year, monthOfYear, dayOfMonth);

        if (year > maxYear ||monthOfYear > maxMonth && year == maxYear||
                 dayOfMonth > maxDay && year == maxYear && monthOfYear == maxMonth){
            view.updateDate(maxYear, maxMonth, maxDay);
            }else if(year < minYear ||monthOfYear < minMonth && year == minYear||
                 dayOfMonth < minDay && year == minYear && monthOfYear == minMonth){
             view.updateDate(minYear, minMonth, minDay );
            }
}

// 在您的Activity类或Fragment中使用此代码,将成员指定为

// 将代码放在以下位置

private int intCurrentYear;
private int intCurrentMonth;
private int intCurrentDay;
private int intMaxYear;
private int intMaxMonth;
private int intMaxDay;
private int intMinYear;
private int intMinDay;
private int intMinMonth;

    DatePickerDialogWithMaxMinRange datePickerDialog= null;
DatePickerDialog.OnDateSetListener datePickerOnDateSetListener;
Calendar myCalendar;

// 在onCreate或其他你想要的地方调用此方法

注意:你需要将listener自定义datepickerdialog传递给datepicker dialog以在选择日期后更新日期

public void setDate() {
    /*
     * Initialise Listener for date set
     */

    datePickerOnDateSetListener = new DatePickerDialog.OnDateSetListener() {
        public void onDateSet(DatePicker view, int year, int monthOfYear,
                int dayOfMonth) {
            edtTxtPlayerBirthDay.setText(new StringBuilder().append(year)
                    .append("-").append(monthOfYear + 1).append("-")
                    .append(dayOfMonth));
        }
    };

    // initialise DatePicker 

    myCalendar = Calendar.getInstance();

    intCurrentYear = myCalendar.get(Calendar.YEAR);
    intCurrentMonth = myCalendar.get(Calendar.MONTH);
    intCurrentDay = myCalendar.get(Calendar.DAY_OF_MONTH);

    intMaxYear =  intCurrentYear - 2000;
    intMaxMonth = intCurrentMonth;
    intMaxDay =  intCurrentDay;

    intMinYear =  intCurrentYear - 1950;
    intMinMonth = intCurrentMonth;
    intMinDay =  intCurrentDay; 

    datePickerDialog = new DatePickerDialogWithMaxMinRange(
            context, datePickerOnDateSetListener,intMinYear,intMinMonth,intMinDay,intMaxYear,intMaxMonth,intMaxDay);
}

在创建日期选择器时,根据您的需求传递mindate和maxdate。 要在按钮单击或任何其他控件中显示日期选择器,请将以下代码放入onclicklistener中...
datePickerDialog.show();

2
兄弟,你知道当你写下 "abc" + 1 + object 时,实际上是新建了一个 StringBuilder()... 呃呃呃... 对吧?那么为什么不直接手动写呢? - Korniltsev Anatoly
@Ramesh 在Android 5.0.1中失败了,因此请提供一些替代方案。 - Zala Janaksinh

5

我找到了一种很酷的方法来设置DatePickerDialogminmax日期。适用于所有Android版本。你只需要根据Android版本返回相应的DatePickerDialog即可。

protected Dialog onCreateDialog(int id)
{
    switch ( id )
    {
        case DATE_DIALOG_ID:
            DatePickerDialog dialog = null;
            if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB )
            {
                dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener()
                {
                    @Override
                    public void onDateSet(DatePicker view, int selectedYear, int selectedMonth, int selectedDate)
                    {
                        mTextView.setText(selectedDate + "/" + selectedMonth + 1 + "/" + selectedYear);
                    }
                }, year, month - 1, date);
                Calendar currentDate = Calendar.getInstance();
                dialog.getDatePicker().setMaxDate(currentDate.getTimeInMillis());
                //If you need you can set min date too
            }
            else
            {
                dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener()
                {
                    @Override
                    public void onDateSet(DatePicker view, int selectedYear, int selectedMonth, int selectedDate)
                    {
                        mTextView.setText(selectedDate + "/" + selectedMonth + 1 + "/" + selectedYear);
                    }
                }, year, month - 1, date)
                {
                    @Override
                    public void onDateChanged(DatePicker view, int year, int month, int day)
                    {
                        if ( year <= maxYear && month + 1 <= maxMonth && date <= maxDate ) //meets your criteria
                        {
                            view.updateDate(year, month, date); //update the date picker to selected date
                        }
                        else
                        {
                            view.updateDate(maxYear, maxMonth - 1, maxDate); // or you update the date picker to previously selected date
                        }
                    }
                };
            }
            return dialog;
    }
    return null;
}

2

编辑您的DatePicker.java文件,添加以下三个代码片段。

声明用于限制最小和最大日期的变量。

// Variables for defining minimum date 
private int minimumDay;
private int minimumMonth;
private int minimumYear;

// Variables for defining maximum date 
private int maximumDay;
private int maximumMonth;
private int maximumYear;

在构造函数之后,您需要重写onDateChanged方法。
// Called every time the user changes DatePicker values
public void onDateChanged(DatePicker view, int year, int monthOfYear, 
        int dayOfMonth) {

    // Test if chosen date is before minimum date
    boolean beforeMinDate = false;
    boolean afterMaxDate = false;

    if(year < minimumYear){
        beforeMinDate = true;
    }
    else if(year == minimumYear){
        if(monthOfYear < minimumMonth){
            beforeMinDate = true;
        }
        else if(monthOfYear == minimumMonth){
            if(dayOfMonth < minimumDay){
                beforeMinDate = true;
            }
        }
    }

    // Test if chosen date is after maximum date
    if(!beforeMinDate){
        if(year > maxYear){
            afterMaxDate = true;
        }
        else if(year == maxYear){
            if(monthOfYear > maxMonth){
                afterMaxDate = true;
            }
            else if(monthOfYear == maxMonth){
                if(dayOfMonth > maxDay){
                    afterMaxDate = true;
                }
            }
        }
    }

    // If chosen date is before minimum date, update the date and internal
    // calendar to minimum date, else, check similarly fot the maximum
    // date, else, use the valid chosen date.
    if(beforeMinDate)
    {
        mCalendar.set(minimumYear, minimumMonth, minimumDay, 
                mCalendar.get(Calendar.HOUR_OF_DAY), 
                mCalendar.get(Calendar.MINUTE));
        updateDate(minimumYear, minimumMonth, minimumDay);
    }
    else if (afterMaxDate)
    {
        mCalendar.set(maximumYear, maximumMonth, maximumDay, 
                mCalendar.get(Calendar.HOUR_OF_DAY), 
                mCalendar.get(Calendar.MINUTE));
        updateDate(maximumYear, maximumMonth, maximumDay);
    }
    else
        mCalendar.set(year, monthOfYear, dayOfMonth, 
                mCalendar.get(Calendar.HOUR_OF_DAY), 
                mCalendar.get(Calendar.MINUTE));
}

现在,为最小和最大日期创建setter方法。
    // Method to define minimum permitted date for the picker.
    public void setMinimumDate(int minimumDay, int minimumMonth, 
            int minimumYear)
    {
        this.minimumDay = minimumDay;
        this.minimumMonth = minimumMonth;
        this.minimumYear = minimumYear;
    }

    //Method to define maximum permitted date for the picker.
    public void setMaximumDate(int maximumDay, int maximumMonth, 
            int maximumYear)
    {
        this.maximumDay = maximumDay;
        this.maximumMonth = maximumMonth;
        this.maximumYear = maximumYear;
    }

第二部分,您在活动中调用日期选择器对话框时,需要设置所需的最小和最大日期。下面的代码将当前日期设置为最小日期,将未来两年设置为最大日期。

    // Define current date as the minimum desired date
    Calendar c = Calendar.getInstance(); 
    int currentDay = c.get(Calendar.DAY_OF_MONTH);
    int currentMonth = c.get(Calendar.MONTH);
    int currentYear = c.get(Calendar.YEAR);
    inicioDateTimePicker.setMinimumDate(currentDay, currentMonth, 
            currentYear);

    // Define two years in the future as the maximum desired date
    Calendar c = Calendar.getInstance(); 
    int currentDay = c.get(Calendar.DAY_OF_MONTH);
    int currentMonth = c.get(Calendar.MONTH);
    int currentYear = c.get(Calendar.YEAR);
    inicioDateTimePicker.setMinimumDate(currentDay, currentMonth, 
            currentYear + 2);

1
你不能这样做。我处理这个问题的方法是使用一个if语句来处理DatePicker:
import android.os.Build.*;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    // (picker is a DatePicker)
    picker.setMinDate(...);
} else {
    Log.w(TAG, "API Level < 11 so not restricting date range...");
}

我最终没有为TimePicker做任何事情。

有什么好消息吗?

SimonVT已经将DatePicker和TimePicker进行了向后兼容,因此您可以在早期的API级别上享受最新的功能:


1

根据@yostyle的答案,我制作了一个方法,用于设置DatePicker的最小和最大日期。 我的DatePicker被用在AlertDialog中,因为我需要一些额外的自定义,但是这个方法可以直接用于任何DatePickerDialog或任何自定义的DatePicker:

/**
     * Compat utility method that will set the minimum date and the maximum date for the DatePicker view.
     * <p/>
     * If the current API is greater than 11, than the normal {@link android.widget.DatePicker#setMinDate(long)} and
     * {@link android.widget.DatePicker#setMaxDate(long)} methods will be used.
     * <p/>
     *
     * @param minCalendar
     *         The minimum date for the picker
     * @param maxCalendar
     *         The maximum date for the picker
     */
    private void initDatePickerCompat(final Calendar minCalendar, final Calendar maxCalendar) {
        if (null == mDatePicker) {
            // Exit early if DatePicker view was not initialized
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            // (mDatePicker is a DatePicker)
            mDatePicker.setMinDate(minCalendar.getTimeInMillis());
            mDatePicker.setMaxDate(maxCalendar.getTimeInMillis());
        } else {
            final int minYear = minCalendar.get(Calendar.YEAR);
            final int minMonth = minCalendar.get(Calendar.MONTH);
            final int minDay = minCalendar.get(Calendar.DAY_OF_MONTH);

            final int maxYear = maxCalendar.get(Calendar.YEAR);
            final int maxMonth = maxCalendar.get(Calendar.MONTH);
            final int maxDay = maxCalendar.get(Calendar.DAY_OF_MONTH);

            mDatePicker.init(minYear, minMonth, minDay, new DatePicker.OnDateChangedListener() {
                @Override
                public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                    Calendar newCalendar = Calendar.getInstance();
                    newCalendar.set(year, monthOfYear, dayOfMonth);

                    if (newCalendar.after(maxCalendar)) {
                        // MAX
                        view.updateDate(maxYear, maxMonth, maxDay);
                    } else if (newCalendar.before(minCalendar)) {
                        // MIN
                        view.updateDate(minYear, minMonth, minDay);
                    } else {
                        // BETWEEN
                        view.updateDate(year, monthOfYear, dayOfMonth);
                    }
                }
            });
        }
    }

请记住,在调用此方法之前应该初始化DatePicker,像这样:
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
mDatePicker.init(year, monthOfYear, dayOfMonth, this);
DateTime minDate = new DateTime();
DateTime maxDate = minDate.plusYears(10);
// Set the minimum and the maximum date for the date picker
initDatePickerCompat(minDate.toCalendar(Locale.getDefault()), maxDate.toCalendar(Locale.getDefault()));

-1

只需使用从日历获取的值(最小值和最大值)来设置DatePiker.MaxDate和DatePiker.MinDate,尝试类似以下的代码:

 DatePickerDialog dialog = new DatePickerDialog();

 Java.Util.TimeZone GMT = new SimpleTimeZone(TimeZoneInfo.Local.BaseUtcOffset.Hours, "GMT"); 
 Calendar maxDate = Calendar.GetInstance(GMT);
 maxDate.Set(DateTime.Now.Year, DateTime.Now.Month - 1, DateTime.Now.Day);

 Calendar minDate = Calendar.GetInstance(GMT);
 minDate.Set(DateTime.Now.Year - 2, DateTime.Now.Month - 1, DateTime.Now.Day);

 dialog.DatePicker.MaxDate = maxDate.TimeInMillis;
 dialog.DatePicker.MinDate = minDate.TimeInMillis;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接