Android原生时间控件DatePicker——月份由英文转数字

来源:互联网 发布:拳皇2002出招优化补丁 编辑:程序博客网 时间:2024/05/24 03:52

网上有很多优秀的开源时间控件,可以满足我们大部分的需求。

但有时候还是会碰到系统自带的DatePicker,这个控件默认的月份显示为英文,如JANUARY、FEBRUARY等。

如何将月份由英文改成数字,这是个好玩的问题。

庖丁解牛

DatePicker并没有提供相关api可以实现我们的需求,所以需要我们自己来分析。

查看DatePicke的源码,它的布局文件是date_picker.xml,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:layout_gravity="center_horizontal"    android:orientation="horizontal"    android:gravity="center">    <LinearLayout android:id="@+id/pickers"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="1"        android:orientation="horizontal"        android:gravity="center">        <!-- Month -->        <NumberPicker            android:id="@+id/month"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginStart="1dip"            android:layout_marginEnd="1dip"            android:focusable="true"            android:focusableInTouchMode="true"            />        <!-- Day -->        <NumberPicker            android:id="@+id/day"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginStart="1dip"            android:layout_marginEnd="1dip"            android:focusable="true"            android:focusableInTouchMode="true"            />        <!-- Year -->        <NumberPicker            android:id="@+id/year"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginStart="1dip"            android:layout_marginEnd="1dip"            android:focusable="true"            android:focusableInTouchMode="true"            />    </LinearLayout>    <!-- calendar view -->    <CalendarView        android:id="@+id/calendar_view"        android:layout_width="245dip"        android:layout_height="280dip"        android:layout_marginStart="44dip"        android:layout_weight="1"        android:focusable="true"        android:focusableInTouchMode="true"        android:visibility="gone"        /></LinearLayout>

可以很轻松地发现,月份就是一个id为month的NumberPicker控件。

DatePicker中以month控件为线索,很快发现NumberPicker下的这个方法:

    /**     * Sets the values to be displayed.     *     * @param displayedValues The displayed values.     */    public void setDisplayedValues(String[] displayedValues) {        ...        ...        ...    }

该方法参数为一个String数组,该数组每一项就是展示的月份数据。

所以如果我们自己调用该方法,传入以数字表示的月份,就达到目的啦!

寻找调用时机

DatePicker源码中,直接调用setDisplayedValues方法的地方有两处,

一处是在构造函数中:

public DatePicker(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        ......        OnValueChangeListener onChangeListener = new OnValueChangeListener() {            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {               ......                updateSpinners();                updateCalendarView();                notifyDateChanged();            }        };       ......        // month        mMonthSpinner = (NumberPicker) findViewById(R.id.month);        mMonthSpinner.setMinValue(0);        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);        mMonthSpinner.setDisplayedValues(mShortMonths);        mMonthSpinner.setOnLongPressUpdateInterval(200);        mMonthSpinner.setOnValueChangedListener(onChangeListener);        mMonthSpinnerInput =(EditText)mMonthSpinner.findViewById(R.id.numberpicker_input);        ......}

mShortMonths就是默认的英文月份,就不展开介绍了。

构造函数中在第X行调用了setDisplayedValues方法,完成了展示月份数据的设置。

同时mMonthSpinner的值监听器为onChangeListener,当月份变化时会回调onValueChange方法,该方法中又会调用updateSpinners方法,这是另一处直接调用setDisplayedValues方法的地方:

private void updateSpinners() {      ......        // make sure the month names are a zero based array        // with the months in the month spinner        String[] displayedValues = Arrays.copyOfRange(mShortMonths,                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);        mMonthSpinner.setDisplayedValues(displayedValues);      ......    }

updateSpinners方法除了会在上述的监听器中被调用,还要其他方法中也会调用,例如:

    /**     * Initialize the state. If the provided values designate an inconsistent     * date the values are normalized before updating the spinners.     *     * @param year The initial year.     * @param monthOfYear The initial month <strong>starting from zero</strong>.     * @param dayOfMonth The initial day of the month.     * @param onDateChangedListener How user is notified date is changed by     *            user, can be null.     */    public void init(int year, int monthOfYear, int dayOfMonth,            OnDateChangedListener onDateChangedListener) {        setDate(year, monthOfYear, dayOfMonth);        updateSpinners();        updateCalendarView();        mOnDateChangedListener = onDateChangedListener;    }        /**     * Sets the maximal date supported by this {@link DatePicker} in     * milliseconds since January 1, 1970 00:00:00 in     * {@link TimeZone#getDefault()} time zone.     *     * @param maxDate The maximal supported date.     */    public void setMaxDate(long maxDate) {        mTempDate.setTimeInMillis(maxDate);        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {            return;        }        mMaxDate.setTimeInMillis(maxDate);        mCalendarView.setMaxDate(maxDate);        if (mCurrentDate.after(mMaxDate)) {            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());            updateCalendarView();        }        updateSpinners();    }

以上所有直接或间接调用setDisplayedValues方法的地方都会将月份重置为英文显示,所以我们自己调用setDisplayedValues方法的时机就是在这些方法被调用之后。

也就是说,我们的调用时机在DatePicker构造函数之后、init()setMaxDate()等方法之后和onDateChanged()方法之中。

轻松实现

知道了在何时调用何方法后,我们来具体实现这一需求。

首先准备好展示的月份数组:

String months[] = {"1月", "2月", "3月", "4月", "5月", "6月",            "7月", "8月", "9月", "10月", "11月", "12月"};

假设mDatePicker就是目标DatePicker控件,因为DatePicker没有提供可以获取到月份控件的api,所以需要自己想办法获取到月份控件,再调用它的setDisplayedValues方法。

分析之前的date_picker.xml文件,可以写出下面这行代码:

((NumberPicker) ((ViewGroup) ((ViewGroup) mDatePicker.getChildAt(0)).getChildAt(0)).getChildAt(0)).setDisplayedValues(months);

通过调用这行代码,就实现了替换掉英文月份的目标!

原创粉丝点击