如何使用其他日历系统来填充DatePicker小部件?

19

是否有办法将DatePicker小部件与其他日历系统一起使用?

我需要一个适用于Jalali(波斯语)日历系统的选择器,但我不知道如何将我的数据馈送给DatePicker

我已经研究了与DatePicker相关的方法,但找不到任何允许我这样做的方法。

我还发现了一个名为android-wheel的自定义小部件,它是一个的小部件,感觉不太本地化,但它允许我实现这一点。

所以,是否有办法拥有一个本地外观的DatePicker小部件,允许我为Jalali日历系统选择日期,并在波斯语中显示月份名称?

更新: 我之前回答了我的问题并解决了问题,但@Mohamad Amin创建了一个很棒的库,我强烈建议您使用他的库(谢谢Mohamad Amin)。


你好Nevercom,你有收到我的问题吗?我使用了这个问题的答案,但是出现了异常,你能帮我吗? - Shayan Pourvatan
1
@Shayanpourvatan 你好,Shayan,我实际上正在使用我下面提供的答案,你遇到了什么问题? - Nevercom
谢谢回复,我认为是他的库出了问题,Android-NumberPicker上发生了错误,在获取资源文件时。 - Shayan Pourvatan
发生错误:位于第14行的XML文件尝试从库中填充布局。 - Shayan Pourvatan
@Shayanpourvatan 开一个新问题并发布 LogCat 输出,做完后告诉我。 - Nevercom
显示剩余7条评论
5个回答

21

由于NumberPicker小部件只能在API 11及以上版本中使用,因此我最终使用了android-numberpicker库。虽然同一作者还提供了android-datepicker,但我无法使用它。

这是我的代码,只需将android-numberpicker添加为库即可。

XML布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linlay1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linlay2"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="horizontal" >

        <net.simonvt.numberpicker.NumberPicker
            android:id="@+id/npYear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </net.simonvt.numberpicker.NumberPicker>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@+id/npMonth"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </net.simonvt.numberpicker.NumberPicker>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@+id/npDay"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </net.simonvt.numberpicker.NumberPicker>
    </LinearLayout>

    <Button
        android:id="@+id/btnDateFrom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="OK" />

</LinearLayout>

Java类:

package ir.aydangostar.supportdesk.activities;

import ir.aydangostar.supportdesk.R;
import ir.aydangostar.supportdesk.utils.JDF;
import net.simonvt.numberpicker.NumberPicker;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.actionbarsherlock.view.Window;

public class DatePickerActivity extends Activity {
    public static final String G_DAY = "gDay";
    public static final String G_MONTH = "gMonth";
    public static final String G_YEAR = "gYear";
    public static final String J_DAY = "jDay";
    public static final String J_MONTH = "jMonth";
    public static final String J_YEAR = "jYear";
    private String[] monthNames = { "فروردین", "اردیبهشت", "خرداد", "تیر",
            "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند" };
    private NumberPicker npDay;
    private NumberPicker npMonth;
    private NumberPicker npYear;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        this.requestWindowFeature((int) Window.FEATURE_NO_TITLE);

        setContentView(R.layout.date_picker);
        NumberPicker.OnValueChangeListener onChangeListener = new NumberPicker.OnValueChangeListener() {



            @Override
            public void onValueChange(NumberPicker picker, int oldVal,
                    int newVal) {
                if (picker == npMonth) {
                    if (newVal <= 6) {
                        npDay.setMaxValue(31);
                    } else {
                        npDay.setMaxValue(30);
                    }
                }


            }
        };
        npYear = (NumberPicker) findViewById(R.id.npYear);
        npMonth = (NumberPicker) findViewById(R.id.npMonth);
        npDay = (NumberPicker) findViewById(R.id.npDay);
        Button btnOk = (Button) findViewById(R.id.btnDateFrom);

        npMonth.setOnValueChangedListener(onChangeListener);
        JDF jdf = new JDF();
        int iranianYear = jdf.getIranianYear();
        int iranianMonth = jdf.getIranianMonth();
        int iranianDay = jdf.getIranianDay();

        npYear.setMinValue(1390);
        npYear.setMaxValue(iranianYear);
        npYear.setWrapSelectorWheel(true);
        npMonth.setMinValue(1);
        npMonth.setMaxValue(12);
        npMonth.setDisplayedValues(monthNames);

        npDay.setMinValue(1);
        npDay.setMaxValue(31);

        npYear.setValue(iranianYear);
        npMonth.setValue(iranianMonth);
        npDay.setValue(iranianDay);

        btnOk.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                int newIrYear = npYear.getValue();
                int newIrMonth = npMonth.getValue();
                int newIrDay = npDay.getValue();

                JDF jdf = new JDF();
                jdf.setIranianDate(newIrYear, newIrMonth, newIrDay);

                Intent returnIntent = new Intent();
                returnIntent.putExtra(J_YEAR, newIrYear);
                returnIntent.putExtra(J_MONTH, newIrMonth);
                returnIntent.putExtra(J_DAY, newIrDay);
                returnIntent.putExtra(G_YEAR, jdf.getGregorianYear());
                returnIntent.putExtra(G_MONTH, jdf.getGregorianMonth());
                returnIntent.putExtra(G_DAY, jdf.getGregorianDay());

                setResult(RESULT_OK, returnIntent);
                finish();

            }
        });
    }

}

我使用了JDF类进行日期转换,这是该类:

package ir.aydangostar.supportdesk.utils;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class JDF {

    /**
     * Main: The default constructor uses the current Gregorian date to
     * initialize the other private memebers of the class (Iranian and Julian
     * dates).
     */
    public JDF() {
        Calendar calendar = new GregorianCalendar();
        setGregorianDate(calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH) + 1,
                calendar.get(Calendar.DAY_OF_MONTH));
    }

    /**
     * Main: This constructor receives a Gregorian date and initializes the
     * other private members of the class accordingly.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     * @return
     */
    public JDF(int year, int month, int day) {
        setGregorianDate(year, month, day);
    }

    /**
     * getIranianYear: Returns the 'year' part of the Iranian date.
     * 
     * @return int
     */
    public int getIranianYear() {
        return irYear;
    }

    /**
     * getIranianMonth: Returns the 'month' part of the Iranian date.
     * 
     * @return int
     */
    public int getIranianMonth() {
        return irMonth;
    }

    /**
     * getIranianDay: Returns the 'day' part of the Iranian date.
     * 
     * @return int
     */
    public int getIranianDay() {
        return irDay;
    }

    /**
     * getGregorianYear: Returns the 'year' part of the Gregorian date.
     * 
     * @return int
     */
    public int getGregorianYear() {
        return gYear;
    }

    /**
     * getGregorianMonth: Returns the 'month' part of the Gregorian date.
     * 
     * @return int
     */
    public int getGregorianMonth() {
        return gMonth;
    }

    /**
     * getGregorianDay: Returns the 'day' part of the Gregorian date.
     * 
     * @return int
     */
    public int getGregorianDay() {
        return gDay;
    }

    /**
     * getJulianYear: Returns the 'year' part of the Julian date.
     * 
     * @return int
     */
    public int getJulianYear() {
        return juYear;
    }

    /**
     * getJulianMonth: Returns the 'month' part of the Julian date.
     * 
     * @return int
     */
    public int getJulianMonth() {
        return juMonth;
    }

    /**
     * getJulianDay() Returns the 'day' part of the Julian date.
     * 
     * @return int
     */
    public int getJulianDay() {
        return juDay;
    }

    /**
     * getIranianDate: Returns a string version of Iranian date
     * 
     * @return String
     */
    public String getIranianDate() {
        return (irYear + "/" + irMonth + "/" + irDay);
    }

    /**
     * getGregorianDate: Returns a string version of Gregorian date
     * 
     * @return String
     */
    public String getGregorianDate() {
        return (gYear + "/" + gMonth + "/" + gDay);
    }

    /**
     * getJulianDate: Returns a string version of Julian date
     * 
     * @return String
     */
    public String getJulianDate() {
        return (juYear + "/" + juMonth + "/" + juDay);
    }

    /**
     * getWeekDayStr: Returns the week day name.
     * 
     * @return String
     */
    public String getWeekDayStr() {
        String weekDayStr[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
                "Friday", "Saturday", "Sunday" };
        return (weekDayStr[getDayOfWeek()]);
    }

    /**
     * toString: Overrides the default toString() method to return all dates.
     * 
     * @return String
     */
    @Override
    public String toString() {
        return (getWeekDayStr() + ", Gregorian:[" + getGregorianDate()
                + "], Julian:[" + getJulianDate() + "], Iranian:["
                + getIranianDate() + "]");
    }

    /**
     * getDayOfWeek: Returns the week day number. Monday=0..Sunday=6;
     * 
     * @return int
     */
    public int getDayOfWeek() {
        return (JDN % 7);
    }

    /**
     * nextDay: Go to next julian day number (JDN) and adjusts the other dates.
     */
    public void nextDay() {
        JDN++;
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * nextDay: Overload the nextDay() method to accept the number of days to go
     * ahead and adjusts the other dates accordingly.
     * 
     * @param days
     *            int
     */
    public void nextDay(int days) {
        JDN += days;
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * previousDay: Go to previous julian day number (JDN) and adjusts the otehr
     * dates.
     */
    public void previousDay() {
        JDN--;
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * previousDay: Overload the previousDay() method to accept the number of
     * days to go backward and adjusts the other dates accordingly.
     * 
     * @param days
     *            int
     */
    public void previousDay(int days) {
        JDN -= days;
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * setIranianDate: Sets the date according to the Iranian calendar and
     * adjusts the other dates.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     */
    public void setIranianDate(int year, int month, int day) {
        irYear = year;
        irMonth = month;
        irDay = day;
        JDN = IranianDateToJDN();
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * setGregorianDate: Sets the date according to the Gregorian calendar and
     * adjusts the other dates.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     */
    public void setGregorianDate(int year, int month, int day) {
        gYear = year;
        gMonth = month;
        gDay = day;
        JDN = gregorianDateToJDN(year, month, day);
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * setJulianDate: Sets the date according to the Julian calendar and adjusts
     * the other dates.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     */
    public void setJulianDate(int year, int month, int day) {
        juYear = year;
        juMonth = month;
        juDay = day;
        JDN = julianDateToJDN(year, month, day);
        JDNToIranian();
        JDNToJulian();
        JDNToGregorian();
    }

    /**
     * IranianCalendar: This method determines if the Iranian (Jalali) year is
     * leap (366-day long) or is the common year (365 days), and finds the day
     * in March (Gregorian Calendar)of the first day of the Iranian year
     * ('irYear').Iranian year (irYear) ranges from (-61 to 3177).This method
     * will set the following private data members as follows: leap: Number of
     * years since the last leap year (0 to 4) Gy: Gregorian year of the
     * begining of Iranian year march: The March day of Farvardin the 1st (first
     * day of jaYear)
     */
    private void IranianCalendar() {
        // Iranian years starting the 33-year rule
        int Breaks[] = { -61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210,
                1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178 };
        int jm, N, leapJ, leapG, jp, j, jump;
        gYear = irYear + 621;
        leapJ = -14;
        jp = Breaks[0];
        // Find the limiting years for the Iranian year 'irYear'
        j = 1;
        do {
            jm = Breaks[j];
            jump = jm - jp;
            if (irYear >= jm) {
                leapJ += (jump / 33 * 8 + (jump % 33) / 4);
                jp = jm;
            }
            j++;
        } while ((j < 20) && (irYear >= jm));
        N = irYear - jp;
        // Find the number of leap years from AD 621 to the begining of the
        // current
        // Iranian year in the Iranian (Jalali) calendar
        leapJ += (N / 33 * 8 + ((N % 33) + 3) / 4);
        if (((jump % 33) == 4) && ((jump - N) == 4))
            leapJ++;
        // And the same in the Gregorian date of Farvardin the first
        leapG = gYear / 4 - ((gYear / 100 + 1) * 3 / 4) - 150;
        march = 20 + leapJ - leapG;
        // Find how many years have passed since the last leap year
        if ((jump - N) < 6)
            N = N - jump + ((jump + 4) / 33 * 33);
        leap = (((N + 1) % 33) - 1) % 4;
        if (leap == -1)
            leap = 4;
    }

    /**
     * IranianDateToJDN: Converts a date of the Iranian calendar to the Julian
     * Day Number. It first invokes the 'IranianCalender' private method to
     * convert the Iranian date to Gregorian date and then returns the Julian
     * Day Number based on the Gregorian date. The Iranian date is obtained from
     * 'irYear'(1-3100),'irMonth'(1-12) and 'irDay'(1-29/31).
     * 
     * @return long (Julian Day Number)
     */
    private int IranianDateToJDN() {
        IranianCalendar();
        return (gregorianDateToJDN(gYear, 3, march) + (irMonth - 1) * 31
                - irMonth / 7 * (irMonth - 7) + irDay - 1);
    }

    /**
     * JDNToIranian: Converts the current value of 'JDN' Julian Day Number to a
     * date in the Iranian calendar. The caller should make sure that the
     * current value of 'JDN' is set correctly. This method first converts the
     * JDN to Gregorian calendar and then to Iranian calendar.
     */
    private void JDNToIranian() {
        JDNToGregorian();
        irYear = gYear - 621;
        IranianCalendar(); // This invocation will update 'leap' and 'march'
        int JDN1F = gregorianDateToJDN(gYear, 3, march);
        int k = JDN - JDN1F;
        if (k >= 0) {
            if (k <= 185) {
                irMonth = 1 + k / 31;
                irDay = (k % 31) + 1;
                return;
            } else
                k -= 186;
        } else {
            irYear--;
            k += 179;
            if (leap == 1)
                k++;
        }
        irMonth = 7 + k / 30;
        irDay = (k % 30) + 1;
    }

    /**
     * julianDateToJDN: Calculates the julian day number (JDN) from Julian
     * calendar dates. This integer number corresponds to the noon of the date
     * (i.e. 12 hours of Universal Time). This method was tested to be good
     * (valid) since 1 March, -100100 (of both calendars) up to a few millions
     * (10^6) years into the future. The algorithm is based on D.A.Hatcher,
     * Q.Jl.R.Astron.Soc. 25(1984), 53-55 slightly modified by K.M. Borkowski,
     * Post.Astron. 25(1987), 275-279.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     * @return int
     */
    private int julianDateToJDN(int year, int month, int day) {
        return (year + (month - 8) / 6 + 100100) * 1461 / 4
                + (153 * ((month + 9) % 12) + 2) / 5 + day - 34840408;
    }

    /**
     * JDNToJulian: Calculates Julian calendar dates from the julian day number
     * (JDN) for the period since JDN=-34839655 (i.e. the year -100100 of both
     * calendars) to some millions (10^6) years ahead of the present. The
     * algorithm is based on D.A. Hatcher, Q.Jl.R.Astron.Soc. 25(1984), 53-55
     * slightly modified by K.M. Borkowski, Post.Astron. 25(1987), 275-279).
     */
    private void JDNToJulian() {
        int j = 4 * JDN + 139361631;
        int i = ((j % 1461) / 4) * 5 + 308;
        juDay = (i % 153) / 5 + 1;
        juMonth = ((i / 153) % 12) + 1;
        juYear = j / 1461 - 100100 + (8 - juMonth) / 6;
    }

    /**
     * gergorianDateToJDN: Calculates the julian day number (JDN) from Gregorian
     * calendar dates. This integer number corresponds to the noon of the date
     * (i.e. 12 hours of Universal Time). This method was tested to be good
     * (valid) since 1 March, -100100 (of both calendars) up to a few millions
     * (10^6) years into the future. The algorithm is based on D.A.Hatcher,
     * Q.Jl.R.Astron.Soc. 25(1984), 53-55 slightly modified by K.M. Borkowski,
     * Post.Astron. 25(1987), 275-279.
     * 
     * @param year
     *            int
     * @param month
     *            int
     * @param day
     *            int
     * @return int
     */
    private int gregorianDateToJDN(int year, int month, int day) {
        int jdn = (year + (month - 8) / 6 + 100100) * 1461 / 4
                + (153 * ((month + 9) % 12) + 2) / 5 + day - 34840408;
        jdn = jdn - (year + 100100 + (month - 8) / 6) / 100 * 3 / 4 + 752;
        return (jdn);
    }

    /**
     * JDNToGregorian: Calculates Gregorian calendar dates from the julian day
     * number (JDN) for the period since JDN=-34839655 (i.e. the year -100100 of
     * both calendars) to some millions (10^6) years ahead of the present. The
     * algorithm is based on D.A. Hatcher, Q.Jl.R.Astron.Soc. 25(1984), 53-55
     * slightly modified by K.M. Borkowski, Post.Astron. 25(1987), 275-279).
     */
    private void JDNToGregorian() {
        int j = 4 * JDN + 139361631;
        j = j + (((((4 * JDN + 183187720) / 146097) * 3) / 4) * 4 - 3908);
        int i = ((j % 1461) / 4) * 5 + 308;
        gDay = (i % 153) / 5 + 1;
        gMonth = ((i / 153) % 12) + 1;
        gYear = j / 1461 - 100100 + (8 - gMonth) / 6;
    }

    private int irYear; // Year part of a Iranian date
    private int irMonth; // Month part of a Iranian date
    private int irDay; // Day part of a Iranian date
    private int gYear; // Year part of a Gregorian date
    private int gMonth; // Month part of a Gregorian date
    private int gDay; // Day part of a Gregorian date
    private int juYear; // Year part of a Julian date
    private int juMonth; // Month part of a Julian date
    private int juDay; // Day part of a Julian date
    private int leap; // Number of years since the last leap year (0 to 4)
    private int JDN; // Julian Day Number
    private int march; // The march day of Farvardin the first (First day of
                        // jaYear)
} // End of Class 'Main'

更新:您还需要在 styles.xml 文件中的 Theme 中为此小部件添加样式:

<item name="numberPickerStyle">@style/NPWidget.Holo.NumberPicker</item>

非常感谢,实现非常有用。(^_-) - Shaahin Ashayeri
@ShaahinAshayeri 很高兴它有所帮助。 - Nevercom
@Nevercom,非常感谢您的代码。但是我在导入部分遇到了问题,因为我是Android编程新手,最终我成功了。现在我想通过这个日期设置textview内容,我该怎么做? - Hamid Talebi
@HamidTalebi,您可以在调用的“Activity”的“OnActivityResult”方法中获取所选日期。 - Nevercom
@Nevercom感谢您分享宝贵的经验和简单而有益的代码。它是否根据所选的月份和年份停用29、30和31日? - SalmanShariati
我使用了你的代码,但我的应用程序停止了。我在这个新问题中启动它:“http://stackoverflow.com/q/37938461/3671748”。而且,在我的代码中也没有`numberPickerStyle`方法。你能帮我吗? - Mina Dahesh

19

最近,我创建了一个新的,其中包含波斯语(希吉日历/太阳历)日期选择器,其设计基于Material Design Pickers。 您可以在库的Github页面中获取更多信息。

DatePickerDialog的屏幕截图:

A **screenshot** from the DatePickerDialog


很奇怪的是,Android默认不支持这个功能,因为在iOS上你可以强制日期选择器显示波斯日期。感谢您的贡献。 - box
@MohamadAmin,我无法在Android Studio中运行您的项目。我从GitHub上下载了它,在提取过程中显示“错误0 * 80010135路径太长”。那么我该如何使用您的代码呢? - Mina Dahesh
请在另一个文件夹中提取zip存档,该文件夹的路径较短,例如在C:\驱动器根目录下。这个错误与Windows有关,事实上Windows无法处理非常长的路径。 - Loqman

6
你可以使用这个库: 波斯范围日期选择器 步骤1.将JitPack存储库添加到您的构建文件中。在repositories的末尾添加到您的根build.gradle中:
allprojects {
    repositories {
        maven { url "https://jitpack.io" }
    }
}

步骤2. 添加依赖项

dependencies {
    implementation 'com.github.ali-sardari:PersianRangeDatePicker:1.3.0'
}

然后在您的Java代码中,您可以像下面这样使用它。

DatePickerDialog datePickerDialog = new DatePickerDialog(MainActivity.this);
datePickerDialog.setSelectionMode(DateRangeCalendarView.SelectionMode.Range);
datePickerDialog.setEnableTimePicker(true);
datePickerDialog.setCanceledOnTouchOutside(true);
datePickerDialog.setOnRangeDateSelectedListener(new DatePickerDialog.OnRangeDateSelectedListener() {
        @Override
        public void onRangeDateSelected(PersianCalendar startDate, PersianCalendar endDate) {
            txtStartDate.setText(startDate.getPersianShortDate());
            txtEndDate.setText(endDate.getPersianShortDate());
        }
});

datePickerDialog.showDialog();

这里输入图片描述

(日期选择器)


这太棒了。 - Hossein Kurd
这是一个非常棒的库。 - Zahra Mirali

1
从现在开始,您可以使用基于DroidPersianCalendar应用程序的PersianCaldroid库。我对这个神奇的应用程序进行了许多更改,将其转化为库,并添加了许多需求功能来满足我的需求,但也是大多数应用程序中常见的。该库提供了波斯日历对话框,即日期选择器,以及波斯日历片段,即用于表示用户事件的小部件。波斯日历片段具有基本API,例如添加带有自定义颜色的事件以进行标记、设置自定义字体、日期单击侦听器、月份更改侦听器等。
有关更多信息,请参阅库的git存储库https://github.com/dariushm2/PersianCaldroid

1

如果你喜欢使用 Android Jetpack Compose,你也可以使用 HeroDatePicker


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