android实现双日期选择控件(可隐藏日,只显示年月)
在安卓开发中,会碰到选开始日期和结束日期的问题。特别是在使用pad时,如果弹出一个dialog,能够同时选择开始日期和结束日期,那将是极好的。我在开发中在datepickerdialog的基础上做了修改,实现了这种dialog。效果如下:
具体实现方法为:
先新建一个安卓项目doubledatepicker,在res/layout文件夹下新建date_picker_dialog.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal" android:paddingtop="10dp" > <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical" android:padding="5dip" > <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始日期" /> <datepicker android:id="@+id/datepickerstart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:calendarviewshown="false" /> </linearlayout> <imageview android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/fenge" /> <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical" android:padding="5dip" > <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="结束日期" /> <datepicker android:id="@+id/datepickerend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:calendarviewshown="false" /> </linearlayout> </linearlayout>
然后,在src的 默认包下新建文件doubledatepickerdialog.java,内容如下:
/* * copyright (c) 2007 the android open source project * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ package com.example.doubledatepicker; import java.lang.reflect.field; import android.app.alertdialog; import android.content.context; import android.content.dialoginterface; import android.content.dialoginterface.onclicklistener; import android.os.bundle; import android.view.layoutinflater; import android.view.view; import android.widget.datepicker; import android.widget.datepicker.ondatechangedlistener; /** * a simple dialog containing an {@link android.widget.datepicker}. * * <p> * see the <a href="{@docroot}guide/topics/ui/controls/pickers.html">pickers</a> * guide. * </p> */ public class doubledatepickerdialog extends alertdialog implements onclicklistener, ondatechangedlistener { private static final string start_year = "start_year"; private static final string end_year = "end_year"; private static final string start_month = "start_month"; private static final string end_month = "end_month"; private static final string start_day = "start_day"; private static final string end_day = "end_day"; private final datepicker mdatepicker_start; private final datepicker mdatepicker_end; private final ondatesetlistener mcallback; /** * the callback used to indicate the user is done filling in the date. */ public interface ondatesetlistener { /** * @param view * the view associated with this listener. * @param year * the year that was set. * @param monthofyear * the month that was set (0-11) for compatibility with * {@link java.util.calendar}. * @param dayofmonth * the day of the month that was set. */ void ondateset(datepicker startdatepicker, int startyear, int startmonthofyear, int startdayofmonth, datepicker enddatepicker, int endyear, int endmonthofyear, int enddayofmonth); } /** * @param context * the context the dialog is to run in. * @param callback * how the parent is notified that the date is set. * @param year * the initial year of the dialog. * @param monthofyear * the initial month of the dialog. * @param dayofmonth * the initial day of the dialog. */ public doubledatepickerdialog(context context, ondatesetlistener callback, int year, int monthofyear, int dayofmonth) { this(context, 0, callback, year, monthofyear, dayofmonth); } public doubledatepickerdialog(context context, int theme, ondatesetlistener callback, int year, int monthofyear, int dayofmonth) { this(context, 0, callback, year, monthofyear, dayofmonth, true); } /** * @param context * the context the dialog is to run in. * @param theme * the theme to apply to this dialog * @param callback * how the parent is notified that the date is set. * @param year * the initial year of the dialog. * @param monthofyear * the initial month of the dialog. * @param dayofmonth * the initial day of the dialog. */ public doubledatepickerdialog(context context, int theme, ondatesetlistener callback, int year, int monthofyear, int dayofmonth, boolean isdayvisible) { super(context, theme); mcallback = callback; context themecontext = getcontext(); setbutton(button_positive, "确 定", this); setbutton(button_negative, "取 消", this); // setbutton(button_positive, // themecontext.gettext(android.r.string.date_time_done), this); seticon(0); layoutinflater inflater = (layoutinflater) themecontext.getsystemservice(context.layout_inflater_service); view view = inflater.inflate(r.layout.date_picker_dialog, null); setview(view); mdatepicker_start = (datepicker) view.findviewbyid(r.id.datepickerstart); mdatepicker_end = (datepicker) view.findviewbyid(r.id.datepickerend); mdatepicker_start.init(year, monthofyear, dayofmonth, this); mdatepicker_end.init(year, monthofyear, dayofmonth, this); // updatetitle(year, monthofyear, dayofmonth); // 如果要隐藏当前日期,则使用下面方法。 if (!isdayvisible) { hidday(mdatepicker_start); hidday(mdatepicker_end); } } /** * 隐藏datepicker中的日期显示 * * @param mdatepicker */ private void hidday(datepicker mdatepicker) { field[] datepickerffields = mdatepicker.getclass().getdeclaredfields(); for (field datepickerfield : datepickerffields) { if ("mdayspinner".equals(datepickerfield.getname())) { datepickerfield.setaccessible(true); object daypicker = new object(); try { daypicker = datepickerfield.get(mdatepicker); } catch (illegalaccessexception e) { e.printstacktrace(); } catch (illegalargumentexception e) { e.printstacktrace(); } // datepicker.getcalendarview().setvisibility(view.gone); ((view) daypicker).setvisibility(view.gone); } } } public void onclick(dialoginterface dialog, int which) { // log.d(this.getclass().getsimplename(), string.format("which:%d", // which)); // 如果是“取 消”按钮,则返回,如果是“确 定”按钮,则往下执行 if (which == button_positive) trynotifydateset(); } @override public void ondatechanged(datepicker view, int year, int month, int day) { if (view.getid() == r.id.datepickerstart) mdatepicker_start.init(year, month, day, this); if (view.getid() == r.id.datepickerend) mdatepicker_end.init(year, month, day, this); // updatetitle(year, month, day); } /** * 获得开始日期的datepicker * * @return the calendar view. */ public datepicker getdatepickerstart() { return mdatepicker_start; } /** * 获得结束日期的datepicker * * @return the calendar view. */ public datepicker getdatepickerend() { return mdatepicker_end; } /** * sets the start date. * * @param year * the date year. * @param monthofyear * the date month. * @param dayofmonth * the date day of month. */ public void updatestartdate(int year, int monthofyear, int dayofmonth) { mdatepicker_start.updatedate(year, monthofyear, dayofmonth); } /** * sets the end date. * * @param year * the date year. * @param monthofyear * the date month. * @param dayofmonth * the date day of month. */ public void updateenddate(int year, int monthofyear, int dayofmonth) { mdatepicker_end.updatedate(year, monthofyear, dayofmonth); } private void trynotifydateset() { if (mcallback != null) { mdatepicker_start.clearfocus(); mdatepicker_end.clearfocus(); mcallback.ondateset(mdatepicker_start, mdatepicker_start.getyear(), mdatepicker_start.getmonth(), mdatepicker_start.getdayofmonth(), mdatepicker_end, mdatepicker_end.getyear(), mdatepicker_end.getmonth(), mdatepicker_end.getdayofmonth()); } } @override protected void onstop() { // trynotifydateset(); super.onstop(); } @override public bundle onsaveinstancestate() { bundle state = super.onsaveinstancestate(); state.putint(start_year, mdatepicker_start.getyear()); state.putint(start_month, mdatepicker_start.getmonth()); state.putint(start_day, mdatepicker_start.getdayofmonth()); state.putint(end_year, mdatepicker_end.getyear()); state.putint(end_month, mdatepicker_end.getmonth()); state.putint(end_day, mdatepicker_end.getdayofmonth()); return state; } @override public void onrestoreinstancestate(bundle savedinstancestate) { super.onrestoreinstancestate(savedinstancestate); int start_year = savedinstancestate.getint(start_year); int start_month = savedinstancestate.getint(start_month); int start_day = savedinstancestate.getint(start_day); mdatepicker_start.init(start_year, start_month, start_day, this); int end_year = savedinstancestate.getint(end_year); int end_month = savedinstancestate.getint(end_month); int end_day = savedinstancestate.getint(end_day); mdatepicker_end.init(end_year, end_month, end_day, this); } }
这些代码是以datepickerdialog.java为基础修改的。总的来说,阅读源码是一种好习惯。这里面最需要注意的是hidday方法,该方法如果调用,则隐藏“日”的选择框,只能选择“年月”。这个方法的实现也比较有难度,需要通过反射,找出datepicker中表示日的字段,并将其设置为隐藏。
还有一点需要注意的是,为了让控件显示更加好看,我用了一张名字为fenge.png的图片,图片在我提供的源码中可以找到。
下面就需要编辑activity_main.xml了,这个内容相当简单,只要一个显示的text和一个button即可,代码如下:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linearlayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <edittext android:id="@+id/et" android:layout_width="fill_parent" android:layout_height="wrap_content" android:cursorvisible="false" android:editable="false" /> <button android:id="@+id/datebtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="日期对话框" /> </linearlayout>
最后,在mainactivity.java中,加入测试代码:
package com.example.doubledatepicker; import java.util.calendar; import android.app.activity; import android.os.bundle; import android.view.view; import android.widget.button; import android.widget.datepicker; import android.widget.textview; public class mainactivity extends activity { button btn; textview et; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); btn = (button) findviewbyid(r.id.datebtn); et = (textview) findviewbyid(r.id.et); btn.setonclicklistener(new view.onclicklistener() { calendar c = calendar.getinstance(); @override public void onclick(view v) { // 最后一个false表示不显示日期,如果要显示日期,最后参数可以是true或者不用输入 new doubledatepickerdialog(mainactivity.this, 0, new doubledatepickerdialog.ondatesetlistener() { @override public void ondateset(datepicker startdatepicker, int startyear, int startmonthofyear, int startdayofmonth, datepicker enddatepicker, int endyear, int endmonthofyear, int enddayofmonth) { string textstring = string.format("开始时间:%d-%d-%d\n结束时间:%d-%d-%d\n", startyear, startmonthofyear + 1, startdayofmonth, endyear, endmonthofyear + 1, enddayofmonth); et.settext(textstring); } }, c.get(calendar.year), c.get(calendar.month), c.get(calendar.date), true).show(); } }); } }
可以看到,在新建doubledatepickerdialog时, 我们实现了一个new doubledatepickerdialog.ondatesetlistener()的匿名类,这个类被doubledatepickerdialog引用,当doubledatepickerdialog中的“确 定”按钮被点击时,就会调用匿名类的ondateset方法。(这也是事件绑定的基本原理)。
doubledatepickerdialog构造函数的最后一个参数,true为显示日期,false为不显示日期。
当最后一个参数为true时,显示效果如下:
当最后一个参数为false时,显示如下
源码下载地址:http://xiazai.jb51.net/201701/yuanma/doubledatepicker_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。