欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android实现双日期选择控件(可隐藏日,只显示年月)

程序员文章站 2024-02-17 16:44:34
在安卓开发中,会碰到选开始日期和结束日期的问题。特别是在使用pad时,如果弹出一个dialog,能够同时选择开始日期和结束日期,那将是极好的。我在开发中在datepicke...

在安卓开发中,会碰到选开始日期和结束日期的问题。特别是在使用pad时,如果弹出一个dialog,能够同时选择开始日期和结束日期,那将是极好的。我在开发中在datepickerdialog的基础上做了修改,实现了这种dialog。效果如下:

android实现双日期选择控件(可隐藏日,只显示年月)

具体实现方法为:

先新建一个安卓项目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时,显示效果如下:

android实现双日期选择控件(可隐藏日,只显示年月)

当最后一个参数为false时,显示如下

android实现双日期选择控件(可隐藏日,只显示年月) 

源码下载地址:http://xiazai.jb51.net/201701/yuanma/doubledatepicker_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。