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

Android使用GridView实现日历的方法

程序员文章站 2024-02-11 13:44:34
在开发中可能会遇到某些情况下需要用到日历的功能,并且还要在日历上加标签什么的,最重要的就是android自带的日历由于各个系统版本不同导致日历的样式也不同,这样就会导致使用...

在开发中可能会遇到某些情况下需要用到日历的功能,并且还要在日历上加标签什么的,最重要的就是android自带的日历由于各个系统版本不同导致日历的样式也不同,这样就会导致使用起来比较麻烦..而且在日历中加标签也不好实现...所以很多时候日历都是自己去实现的...由于自定义日历会比较麻烦...这里就教大家使用gridview来实现,主要是我们比较熟悉这个控件...到时候也可以根据自己的情况进行封装为自定义view

下面就先看看效果图.由于是从项目中抽取出来的,某些地方定制性比较强, 可以根据需求自行修改

效果图

Android使用GridView实现日历的方法

图中的红点就是标签,蓝色背景就是选中的意思.

下面开始撸代码:

先上核心的gridview的适配器:

calendaradapter.java

/**
 * 日历gridview中的每一个item显示的textview
 */
public class calendaradapter extends baseadapter {

  private static string tag = "calendaradapter";
  private boolean isleapyear = false; //是否为闰年 
  private int daysofmonth = 0;   //某月的天数 
  private int dayofweek = 0;    //具体某一天是星期几 
  private int lastdaysofmonth = 0; //上一个月的总天数 
  private context context;
  private string[] daynumber = new string[42]; //一个gridview中的日期存入此数组中 
  private specialcalendar sc = null;
  private int currentyear = 0;
  private int currentmonth = 0;
  /**
   * 当前选中的日期位置
   */
  private int currentflag = -1;
  /**
   * 当前选中天的字符串 例:20170830
   */
  private string currentdaystr;
  private simpledateformat sdf = new simpledateformat("yyyy-m-d");
  private set<integer> schdatetagflag = new arrayset<>(); //存储当月所有的日程日期(标签)
  private string showyear = "";  //用于在头部显示的年份
  private string showmonth = ""; //用于在头部显示的月份 
  private string animalsyear = "";
  private string leapmonth = "";  //闰哪一个月 
  private set<string> mset = null;
  /**
   * 距离当前月的差(上一个月-1,当前月0,下一个月+1)
   */
  private int jumpmonth = 0;


  public calendaradapter(context context, int year, int month, string currentdaystr) {
    this.context = context;
    sc = new specialcalendar();
    currentyear = year;
    currentmonth = month; //得到跳转到的月份
    this.currentdaystr = currentdaystr;
    getcalendar(currentyear, currentmonth);
  }

  @override
  public int getcount() {
    return daynumber.length;
  }

  @override
  public object getitem(int position) {
    return position;
  }

  @override
  public long getitemid(int position) {
    return position;
  }

  @override
  public view getview(int position, view convertview, viewgroup parent) {
    viewholder myviewholder = null;
    if (convertview == null || convertview.gettag() == null) {
      convertview = layoutinflater.from(context).inflate(r.layout.item_select_time, null);
      myviewholder = new viewholder(convertview);
      convertview.settag(myviewholder);
    } else {
      myviewholder = (viewholder) convertview.gettag();
    }
    myviewholder.midtvitemselecttimeday.settext(daynumber[position]);
    myviewholder.midtvitemselecttimeday.settextcolor(color.gray);//不是当前月为灰
    if (position < daysofmonth + dayofweek && position >= dayofweek) {
      // 当前月信息显示 
      myviewholder.midtvitemselecttimeday.settextcolor(color.black);// 当月字体设黑
      myviewholder.midtvitemselecttimeday.settag(true);// 当月字体设黑
    }else {
      myviewholder.midtvitemselecttimeday.settag(false);// 当月字体设黑
    }

    if (currentflag != -1 && currentflag == position) {
      //设置当天的背景
      myviewholder.midtvitemselecttimeday.setbackgroundresource(r.color.mainmenu);
      myviewholder.midtvitemselecttimeday.settextcolor(color.white);
    } else {
      myviewholder.midtvitemselecttimeday.setbackgroundcolor(0);
    }

    //显示小圆点
    if (schdatetagflag != null && schdatetagflag.size() > 0) {
      if (schdatetagflag.contains(position)) {
        if (myviewholder.midimgitemselecttimelogo.getvisibility()!=view.visible) {
          myviewholder.midimgitemselecttimelogo.setvisibility(view.visible);
        }
      } else {
        if (myviewholder.midimgitemselecttimelogo.getvisibility()!=view.gone) {
          myviewholder.midimgitemselecttimelogo.setvisibility(view.gone);
        }
      }
    } else {
      if (myviewholder.midimgitemselecttimelogo.getvisibility()!=view.gone) {
        myviewholder.midimgitemselecttimelogo.setvisibility(view.gone);
      }
    }


    return convertview;
  }


  /**
   * 下一个月
   */
  public void addmonth() {
    jumpmonth++;
  }

  /**
   * 上一个月
   */
  public void lessmonth() {
    jumpmonth--;
  }


  /**
   * 更新日历数据
   */
  public void updatamonth() {
    int stepyear;
    int stepmonth = currentmonth + jumpmonth;
    if (stepmonth > 0) {
      //下一个月
      if (stepmonth % 12 == 0) {
        stepyear = currentyear + stepmonth / 12 - 1;
        stepmonth = 12;
      } else {
        stepyear = currentyear + stepmonth / 12;
        stepmonth = stepmonth % 12;
      }
    } else {
      //上一个月
      stepyear = currentyear - 1 + stepmonth / 12;
      stepmonth = stepmonth % 12 + 12;
    }
    getcalendar(stepyear, stepmonth);
  }

  /**
   * 得到某年的某月的天数且这月的第一天是星期几
   *
   * @param year
   * @param month
   */
  private void getcalendar(int year, int month) {
    isleapyear = sc.isleapyear(year);       //是否为闰年 
    daysofmonth = sc.getdaysofmonth(isleapyear, month); //某月的总天数 
    dayofweek = sc.getweekdayofmonth(year, month);   //某月第一天为星期几 
    lastdaysofmonth = sc.getdaysofmonth(isleapyear, month - 1); //上一个月的总天数
    getweek(year, month);
  }

  /**
   * 将一个月中的每一天的值添加入数组daynuber中
   *
   * @param year
   * @param month
   */
  private void getweek(int year, int month) {
    schdatetagflag.clear();
    currentflag = -1;
    int j = 1;
    //得到当前月的所有日程日期(这些日期需要标记)
    for (int i = 0; i < daynumber.length; i++) {
      if (i < dayofweek) { //前一个月
        int temp = lastdaysofmonth - dayofweek + 1;
        daynumber[i] = (temp + i) + "";
      } else if (i < daysofmonth + dayofweek) {//本月
        int day = i - dayofweek + 1;  //得到的日期
        daynumber[i] = i - dayofweek + 1 + "";
        //对于当前月才去标记当前日期 
        string yearstr = string.valueof(year);
        string monthstr =getstr(string.valueof(month),2);
        string daystr =getstr(string.valueof(day),2);
        string timeall = yearstr + monthstr + daystr;
        if (timeall.equals(currentdaystr)) {//判断选中的位置
          currentflag = i;
        }
        if (mset != null && mset.size() > 0) {
          for (string s : mset) {//迭代器遍历判断是否需要带标签
            if (timeall.equals(s)) {
              schdatetagflag.add(i);
            }
          }
        }
        setshowyear(yearstr);
        setshowmonth(string.valueof(month));
      } else {  //下一个月
        daynumber[i] = j + "";
        j++;
      }
    }
  }


  /**
   * 获取当前时间 样式:20170830
   * @param position
   * @return
   */
  public string getitemtime(int position) {
    string month = getstr(getshowmonth(), 2);
    string day = getstr(getdatebyclickitem(position), 2);
    return getshowyear() + month + day;

  }

  /**
   * 保留n位整数,不足前面补0
   *
   * @param file string
   * @param bit 位数
   * @return
   */
  public static string getstr(string file,int bit) {
    while (file.length() < bit)
      file = "0" + file;
    return file;
  }

  /**
   * 点击每一个item时返回item中的日期
   *
   * @param position
   * @return
   */
  public string getdatebyclickitem(int position) {
    return daynumber[position];
  }

  /**
   * 在点击gridview时,得到这个月中第一天的位置
   *
   * @return
   */
  public int getstartpositon() {
    return dayofweek + 7;
  }

  /**
   * 在点击gridview时,得到这个月中最后一天的位置
   *
   * @return
   */
  public int getendposition() {
    return (dayofweek + daysofmonth + 7) - 1;
  }

  public string getshowyear() {
    return showyear;
  }

  public void setshowyear(string showyear) {
    this.showyear = showyear;
  }

  public string getshowmonth() {
    return showmonth;
  }

  public void setshowmonth(string showmonth) {
    this.showmonth = showmonth;
  }

  public string getanimalsyear() {
    return animalsyear;
  }

  public void setanimalsyear(string animalsyear) {
    this.animalsyear = animalsyear;
  }

  public string getleapmonth() {
    return leapmonth;
  }

  public void setleapmonth(string leapmonth) {
    this.leapmonth = leapmonth;
  }


  public set<string> getset() {
    return mset;
  }

  public void setset(set<string> set) {
    mset = set;
  }

  static class viewholder {
    @bindview(r.id.id_img_item_select_time_logo)
    imageview midimgitemselecttimelogo;
    @bindview(r.id.id_tv_item_select_time_day)
    textview midtvitemselecttimeday;

    viewholder(view view) {
      butterknife.bind(this, view);
    }
  }
}

日历工具类:

/**
 * 日历工具类
 */
public class specialcalendar {
 
  private int daysofmonth = 0;   //某月的天数 
  private int dayofweek = 0;    //具体某一天是星期几 

  /**
   * 判断是否为闰年
   * @param year
   * @return
   */
  public boolean isleapyear(int year) {
    if (year % 100 == 0 && year % 400 == 0) { 
      return true; 
    } else if (year % 100 != 0 && year % 4 == 0) { 
      return true; 
    } 
    return false; 
  }

  /**
   * 得到某月有多少天数
   * @param isleapyear
   * @param month
   * @return
   */
  public int getdaysofmonth(boolean isleapyear, int month) {
    switch (month) { 
    case 1: 
    case 3: 
    case 5: 
    case 7: 
    case 8: 
    case 10: 
    case 12: 
      daysofmonth = 31; 
      break; 
    case 4: 
    case 6: 
    case 9: 
    case 11: 
      daysofmonth = 30; 
      break; 
    case 2: 
      if (isleapyear) { 
        daysofmonth = 29; 
      } else { 
        daysofmonth = 28; 
      } 
 
    } 
    return daysofmonth; 
  }

  /**
   * 指定某年中的某月的第一天是星期几
   * @param year
   * @param month
   * @return
   */
  public int getweekdayofmonth(int year, int month){
    calendar cal = calendar.getinstance();
    cal.set(year, month-1, 1); 
    dayofweek = cal.get(calendar.day_of_week)-1; 
    return dayofweek; 
  } 
   
   
} 

布局文件:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">

  <include
    layout="@layout/layout_public_finish_menu"
    />

  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:background="@color/bg_home_gone_menu"
    android:gravity="center"
    android:orientation="horizontal"
    >

    <imageview
      android:id="@+id/id_img_select_time_less"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      android:src="@mipmap/ic_sd_time_less"
      android:background="@drawable/selector_public_btn_bg"
      />

    <textview
      android:id="@+id/id_tv_select_time_show"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_weight="4"
      android:gravity="center"
      android:text="年月"
      android:textcolor="@color/white"
      android:textsize="@dimen/default_big"
      />

    <imageview
      android:id="@+id/id_img_select_time_add"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      android:src="@mipmap/ic_sd_time_add"
      android:background="@drawable/selector_public_btn_bg"
      />

  </linearlayout>


  <gridview
    android:id="@+id/id_gv_select_item"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_rectangle_null_black_1"
    android:clickable="true"
    android:gravity="center"
    android:layout_gravity="center"
    android:clipchildren="true"
    android:listselector="@null"
    android:numcolumns="7"
    android:padding="1dp"
    android:layout_margin="5dp"
    android:stretchmode="columnwidth"
    />


</linearlayout>

item布局

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bg_rectangle_null_black_1">

  <textview
    android:id="@+id/id_tv_item_select_time_day"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:text="天"
    android:textsize="@dimen/default_big"
    android:layout_margin="1dp"
    android:textstyle="bold"
    />

  <imageview
    android:id="@+id/id_img_item_select_time_logo"
    android:layout_width="5dp"
    android:layout_height="5dp"
    android:layout_margin="3dp"
    android:src="@drawable/shap_doorbell_oval_red"
    android:visibility="gone"
    />
</relativelayout>

布局只供参考...可以根据需求进行修改

下面就看看简单的调用

 //传入当前的年,月..已经选中的时间(20170830)
 madapter = new calendaradapter(mcontext, year_c, month_c, currentdaystr);
 midgvselectitem.setadapter(madapter);

 /**
   * gridview item的点击事件
   */
  private class mygvlistener implements adapterview.onitemclicklistener {

    @override
    public void onitemclick(adapterview<?> parent, view view, int position, long id) {
      textview mtv = (textview) view.findviewbyid(r.id.id_tv_item_select_time_day);
      boolean isonclick = (boolean) mtv.gettag();
      if (isonclick) {
        string time = madapter.getitemtime(position);
        intent mintent = getintent();
        mintent.putextra("filedate", time);
        setresult(appstart.sdva_sdta, mintent);
        finish();
        log.i(tag,"当前选择的时间:" + time);
      }
    }
  }


 /**
   * 点击事件逻辑处理
   */
  private class mylistener implements view.onclicklistener {
    @override
    public void onclick(view v) {
      switch (v.getid()) {

        //上一个月
        case r.id.id_img_select_time_less:
          madapter.lessmonth();
          mhandler.sendemptymessage(updata_time);
          addtexttotoptextview(midtvselecttimeshow);
          break;

        //下一个月
        case r.id.id_img_select_time_add:
          madapter.addmonth();
          mhandler.sendemptymessage(updata_time);
          addtexttotoptextview(midtvselecttimeshow);
          break;


      }
    }
  }

private set<string> dayeventcount = new hashset<>();
//设置需要显示标签的实际
 madapter.setset(dayeventcount);

//更新
  @override
  protected void uihandlermessage(message msg) {

    switch (msg.what) {
      case updata_time:
        madapter.updatamonth();
        madapter.notifydatasetchanged();
        break;

    }

  }

调用部分的代码由于是从项目中直接复制出来的..代码的前后没有什么关联性,主要是说明功能的..请根据自己的项目进行调整..

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