Android项目实战(二十九)(酒店预定日期选择)

赋料扬雄敌,诗看子建亲。这篇文章主要讲述Android项目实战(二十九):酒店预定日期选择相关的知识,希望能为你提供帮助。
原文:Android项目实战(二十九):酒店预定日期选择先看需求效果图:

Android项目实战(二十九)(酒店预定日期选择)

文章图片
     
Android项目实战(二十九)(酒店预定日期选择)

文章图片
       
Android项目实战(二十九)(酒店预定日期选择)

文章图片
 
 
 
几个需求点:
1、显示当月以及下个月的日历 (可自行拓展更多月份)
2、首次点击选择“开始日期”,再次点击选择"结束日期"
(1)、如果“开始日期” “结束日期” 相同 
Android项目实战(二十九)(酒店预定日期选择)

文章图片

(2)、如果“开始日期” “结束日期” 不同,且“结束日期” 晚于 “开始日期” 
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
(3)、如果“结束日期” 早于 “开始日期” ,重置当前 日期 为 “开始日期”
 
3、选择的“开始日期” “结束日期” 显示在 
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
难点:
1、 获取当月以及下个月的日历,一个月多少天,每天星期几
2、 判断每个日子的点 与   “开始日期” “结束日期” 的关系,用于显示背景色
 
技术储备:
1、浅谈RecyclerView(完美替代ListView,GridView)
2、Android项目实战(十三):浅谈EventBus
 
-----------------------------------------------------------------------------------------------------------------------
 
实现思路:
1、一个外部RecyclerView 用于显示 日历,每一个item 都用于显示一个月的日历             ,下面都称为 外部RecyclerView
2、外部RecyclerView的每一个Item 内再用一个RecyclerView显示该月的所有日期,每一天都是一个item   ,下面都称为 内部RecyclerView
3、点击内部RecyclerView的item 日期,添加监听事件,根据是否开始、结束、中间日期来显示 相应的选中背景
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
 
代码实现:
1、代码框架总览
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
2、实体类
(1)、月份类,外部RecyclerView的数据源实体类
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
/** * Created by xqx on 2017/1/17. * 代表日历上的每一个月份 */ public class MonthTimeEntity {private int year; //该月份 属于哪一年 private int month; // 该月 是哪一个月份public MonthTimeEntity(int year, int month) { this.year = year; this.month = month; }public int getYear() { return year; }public void setYear(int year) { this.year = year; }public int getMonth() { return month; }public void setMonth(int month) { this.month = month; } }

MonthTimeEntity.java(2)、日期类,内部RecyclerView的数据源实体类
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
/** * Created by xqx on 2017/1/17. * 日历中每一个月中的 每一个天数 */ public class DayTimeEntity { private int day ; //日期,几号 private int month; //属于的月份 private int year; //属于的年份private int monthPosition; //属于的月份位置,注意是该日期属于的月份在外层列表中的position,不是月份 private int dayPosition; //属于的日期位置,注意是该日期在每个月(内层列表)中的位置public DayTimeEntity(int day, int month, int year, int monthPosition) { this.day = day; this.month = month; this.year = year; this.monthPosition = monthPosition; }public int getDay() { return day; }public void setDay(int day) { this.day = day; }public int getMonth() { return month; }public void setMonth(int month) { this.month = month; }public int getYear() { return year; }public void setYear(int year) {this.year = year; }public int getMonthPosition() { return monthPosition; }public void setMonthPosition(int monthPosition) { this.monthPosition = monthPosition; }public int getDayPosition() { return dayPosition; }public void setDayPosition(int dayPosition) { this.dayPosition = dayPosition; }}

DayTimeEntity.java(3)、更新类,用于选择 “开始日期”、“结束日期”之后的刷新适配器操作
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
/** * Created by xqx on 2017/1/17. * 用于EventBus发送消息 */ public class UpdataCalendar { }

UpdataCalendar.java 
 
3、主要实现
(1)、主界面布局 
上面就是普通的布局形式,日历用一个RecyclerView显示,这个列表的每一个item都用于显示一个月份的所有天数
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > < !--标题栏--> < RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="6dp" android:background="@color/white" > < !--标题--> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="预定日期" android:layout_centerInParent="true" android:textSize="20sp" /> < /RelativeLayout> < ImageView android:layout_width="match_parent" android:layout_height="1dp" android:background="#d9d9d9" /> < RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#f2f4f7" android:paddingTop="20dp" > < TextView android:id="@+id/plan_time_txt_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始\\n时间" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginLeft="87dp" android:layout_marginStart="87dp" android:background="@mipmap/bg_white_circle" android:gravity="center" /> < TextView android:id="@+id/plan_time_txt_stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="结束\\n时间" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginRight="74dp" android:layout_marginEnd="74dp" android:background="@mipmap/bg_white_circle" android:gravity="center"/> < /RelativeLayout> < LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="#f2f4f7" android:paddingTop="20dp" android:paddingBottom="20dp" android:paddingLeft="20dp" android:paddingRight="20dp" > < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="S" android:gravity="center" /> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="M" android:gravity="center" /> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="T" android:gravity="center" /> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="W" android:gravity="center" /> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="T" android:gravity="center" /> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="F" android:gravity="center"/> < TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="S" android:gravity="center" /> < /LinearLayout> < android.support.v7.widget.RecyclerView android:id="@+id/plan_time_calender" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:paddingLeft="20dp" android:paddingRight="20dp" > < /android.support.v7.widget.RecyclerView> < /LinearLayout>

acticity_main.xml 
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
(2)、日历外部RecyclerView的ViewHolder类,可以看出外层RecyclerView 的 item 只需要一个TextView显示几年几月 和 一个RecyclerView显示该月的天数即可
Android项目实战(二十九)(酒店预定日期选择)

文章图片

Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
import android.content.Context; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.TextView; /** * Created by xqxon 2017/1/17. */ public class MonthTimeViewHolder extends RecyclerView.ViewHolder{public TextView plan_time_txt_month; //文本 2018-1 public RecyclerView plan_time_recycler_content ; //月份里面详细日期的列表 public Context context; //上下文public MonthTimeViewHolder(View itemView, Context context) { super(itemView); this.context = context; plan_time_recycler_content = (RecyclerView) itemView.findViewById(R.id.plan_time_recycler_content); plan_time_txt_month = (TextView) itemView.findViewById(R.id.plan_time_txt_month); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(context, 7,// 每行显示item项数目 GridLayoutManager.VERTICAL, //水平排列 false ); plan_time_recycler_content.setLayoutManager(layoutManager); } }

MonthTimeViewHolder  
(3)、日历外部RecyclerView的item 布局文件
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> < TextView android:id="@+id/plan_time_txt_month" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/blue" android:textSize="16sp" android:text="Aug 2017" android:layout_marginTop="10dp" android:layout_marginLeft="20dp" android:layout_marginBottom="10dp" /> < android.support.v7.widget.RecyclerView android:id="@+id/plan_time_recycler_content" android:layout_width="match_parent" android:layout_height="wrap_content" > < /android.support.v7.widget.RecyclerView> < /LinearLayout>

item_recycler_timeplan
Android项目实战(二十九)(酒店预定日期选择)

文章图片

 
(4)、Activity
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
public class MonthTimeActivity extends Activity {private ImageButton back; private TextView startTime; //开始时间 private TextView stopTime; //结束时间private RecyclerView reycycler; private MonthTimeAdapter adapter; private ArrayList< MonthTimeEntity> datas; public static DayTimeEntity startDay; public static DayTimeEntity stopDay; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); EventBus.getDefault().register(this); }private void initData() { startDay = new DayTimeEntity(0,0,0,0); stopDay = new DayTimeEntity(-1,-1,-1,-1); datas = new ArrayList< > (); Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH)+1; c.add(Calendar.MONTH,1); int nextYear = c.get(Calendar.YEAR); int nextMonth = c.get(Calendar.MONTH)+1; datas.add(new MonthTimeEntity(year,month)); //当前月份 datas.add(new MonthTimeEntity(nextYear,nextMonth)); //下个月 adapter = new MonthTimeAdapter(datas, MonthTimeActivity.this); reycycler.setAdapter(adapter); }private void initView() { startTime = (TextView) findViewById(R.id.plan_time_txt_start); stopTime = (TextView) findViewById(R.id.plan_time_txt_stop); reycycler = (RecyclerView) findViewById(R.id.plan_time_calender); LinearLayoutManager layoutManager = new LinearLayoutManager(this,// 上下文 LinearLayout.VERTICAL,//垂直布局, false); reycycler.setLayoutManager(layoutManager); }public void onEventMainThread(UpdataCalendar event) { adapter.notifyDataSetChanged(); startTime.setText(startDay.getMonth()+"月"+startDay.getDay()+"日"+"\\n"); if (stopDay.getDay() == -1) { stopTime.setText("结束"+"\\n"+"时间"); }else{ stopTime.setText(stopDay.getMonth() + "月" + stopDay.getDay() + "日" + "\\n"); } }@Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }

MonthTimeActivity.java  几个核心点:
 1、 两个静态变量的类 用于标记   开始日期和结束日期,和每个日子进行对比,显示不同的背景色
public static DayTimeEntity startDay; //开始日期 public static DayTimeEntity stopDay; //结束日期

    2、数据源的初始化
private void initData() { startDay = new DayTimeEntity(0,0,0,0); stopDay = new DayTimeEntity(-1,-1,-1,-1); //注意这里参数都为 -1不是随便设的 ,后面会用到 datas = new ArrayList< > (); Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH)+1; // 获得当前月份的信息, 属于哪一年,哪一月c.add(Calendar.MONTH,1); int nextYear = c.get(Calendar.YEAR); int nextMonth = c.get(Calendar.MONTH)+1; // 获得当前月份的下一个月份的信息, 属于哪一年,哪一月。可以以此类推不限制于 2个月份datas.add(new MonthTimeEntity(year,month)); //当前月份的对象,对象里信息包括:哪一年,哪一月 datas.add(new MonthTimeEntity(nextYear,nextMonth)); //下个月份的对象 adapter = new MonthTimeAdapter(datas, MonthTimeActivity.this); reycycler.setAdapter(adapter); }


(5)、日历外部RecyclerView的适配器Adapter
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
/** * Created by xqx on 2017/1/17. */ public class MonthTimeAdapter extends RecyclerView.Adapter< MonthTimeViewHolder> {private ArrayList< MonthTimeEntity> datas; private Context context; public MonthTimeAdapter(ArrayList< MonthTimeEntity> datas, Context context) { this.datas = datas; this.context = context; }@Override public MonthTimeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MonthTimeViewHolder ret = null; // 不需要检查是否复用,因为只要进入此方法,必然没有复用 // 因为RecyclerView 通过Holder检查复用 View v = LayoutInflater.from(context).inflate(R.layout.item_recycler_timeplan, parent, false); ret = new MonthTimeViewHolder(v,context); return ret; }@Override public void onBindViewHolder(MonthTimeViewHolder holder, int position) { MonthTimeEntity monthTimeEntity = datas.get(position); holder.plan_time_txt_month.setText(monthTimeEntity.getYear()+"--"+ monthTimeEntity.getMonth()); //显示 几年--几月 //得到该月份的第一天 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, monthTimeEntity.getYear()); //指定年份 calendar.set(Calendar.MONTH, monthTimeEntity.getMonth() - 1); //指定月份 Java月份从0开始算 calendar.set(Calendar.DAY_OF_MONTH,1); // 指定天数 ,这三行是为了得到 这一年这一月的第一天int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); //得到该月份第一天 是星期几 ArrayList< DayTimeEntity> days = new ArrayList< DayTimeEntity> (); for (int i = 0; i < dayOfWeek-1; i++) {// days.add(new DayTimeEntity(0, monthTimeEntity.getMonth(), monthTimeEntity.getYear(),position)); } calendar.add(Calendar.MONTH, 1); // 加一个月,变为下月的1号 calendar.add(Calendar.DATE, -1); // 减去一天,变为当月最后一天 for (int i = 1; i < = calendar.get(Calendar.DAY_OF_MONTH); i++) {//添加 该月份的天数一号 到 该月的最后一天 days.add(new DayTimeEntity(i, monthTimeEntity.getMonth(), monthTimeEntity.getYear(),position)); }DayTimeAdapter adapter = new DayTimeAdapter(days,context); holder.plan_time_recycler_content.setAdapter(adapter); }@Override public int getItemCount() { int ret = 0; if (datas!=null){ ret = datas.size(); } return ret; } }

MonthTimeAdapter.java 
核心代码:
//得到该月份的第一天 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, monthTimeEntity.getYear()); //指定年份 calendar.set(Calendar.MONTH, monthTimeEntity.getMonth() - 1); //指定月份 Java月份从0开始算 calendar.set(Calendar.DAY_OF_MONTH,1); // 指定天数 ,这三行是为了得到 这一年这一月的第一天int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); //得到该月份第一天 是星期几

for (int i = 0; i < dayOfWeek-1; i++) {// days.add(new DayTimeEntity(0, monthTimeEntity.getMonth(), monthTimeEntity.getYear(),position)); //填充空白天数 }

目的是实现 :比如第一天是星期3 ,那么日历上 星期日,星期一,星期二的位置 要为空白   
意味着一个天数的item getDay() == 0 ,说明这天是空白天数 
 
calendar.add(Calendar.MONTH, 1); // 加一个月,变为下月的1号 calendar.add(Calendar.DATE, -1); // 减去一天,变为当月最后一天 for (int i = 1; i < = calendar.get(Calendar.DAY_OF_MONTH); i++) {// 添加 该月份的天数一号 到 该月的最后一天 days.add(new DayTimeEntity(i, monthTimeEntity.getMonth(), monthTimeEntity.getYear(),position)); }

目的是实现:得到该月份的最后一天是几号,然后从1号到最后一天都作为数据源添加到内部的recyclerview中。
 
以上是外层Recyclerview(每一个Item是一个月份)的相关代码
-------------------------------------------------------------------------------------------------
 
(6)   外部RecyclerView的 Item中的内部RecyclerView ,每一个item都是该月份的一天
  item布局:   就只有一个textview ,用于显示 几号
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:layout_marginBottom="2dp" android:paddingTop="6dp" android:paddingBottom="6dp" android:id="@+id/select_ly_day" > < TextView android:id="@+id/select_txt_day" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" android:layout_gravity="center" android:gravity="center" /> < /LinearLayout>

item_recycler_selectday.xml 
(7)内部RecyclerView的ViewHolder
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
** * Created by xqx on 2017/1/17. * */ public class DayTimeViewHolder extends RecyclerView.ViewHolder{public TextView select_txt_day; //日期文本 public LinearLayout select_ly_day; //父容器 , 用于点击日期public DayTimeViewHolder(View itemView) { super(itemView); select_ly_day = (LinearLayout) itemView.findViewById(R.id.select_ly_day); select_txt_day = (TextView) itemView.findViewById(R.id.select_txt_day); } }

DayTimeViewHolder.java 
(8)内部RecyclerView的适配器Adapter
Android项目实战(二十九)(酒店预定日期选择)

文章图片
Android项目实战(二十九)(酒店预定日期选择)

文章图片
package com.maiji.calendardemo.selectTime; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.maiji.calendardemo.MonthTimeActivity; import com.maiji.calendardemo.R; import com.maiji.calendardemo.entity.DayTimeEntity; import com.maiji.calendardemo.entity.UpdataCalendar; import java.util.ArrayList; import de.greenrobot.event.EventBus; /** * Created by xqx on 2017/1/17. */ public class DayTimeAdapter extends RecyclerView.Adapter< DayTimeViewHolder> {private ArrayList< DayTimeEntity> days; private Context context; public DayTimeAdapter(ArrayList< DayTimeEntity> days, Context context) { this.days = days; this.context = context; }@Override public DayTimeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { DayTimeViewHolder ret = null; // 不需要检查是否复用,因为只要进入此方法,必然没有复用 // 因为RecyclerView 通过Holder检查复用 View v = LayoutInflater.from(context).inflate(R.layout.item_recycler_selectday, parent, false); ret = new DayTimeViewHolder(v); return ret; }@Override public void onBindViewHolder(final DayTimeViewHolder holder, final int position) { final DayTimeEntity dayTimeEntity = days.get(position); //显示日期 if (dayTimeEntity.getDay()!=0) { holder.select_txt_day.setText(dayTimeEntity.getDay() + ""); holder.select_ly_day.setEnabled(true); }else{ holder.select_ly_day.setEnabled(false); } holder.select_ly_day.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (MonthTimeActivity.startDay.getYear() == 0 ){// 第一次点击开始的位置,因为开始默认参数是 0,0,0,0 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); // 该item 天数的 年月日等信息赋给开始日期 MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); }else if(MonthTimeActivity.startDay.getYear()> 0 & & MonthTimeActivity.stopDay.getYear() ==-1){//已经点击了开始 ,点击结束位置,(默认结束位置-1,-1,-1,-1 说明还没有点击结束位置) if (dayTimeEntity.getYear()> MonthTimeActivity.startDay.getYear()) { //如果选中的年份大于开始的年份,说明结束日期肯定大于开始日期 ,合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else if (dayTimeEntity.getYear() == MonthTimeActivity.startDay.getYear()){ //如果选中的年份 等于 选中的年份 if (dayTimeEntity.getMonth()> MonthTimeActivity.startDay.getMonth()){ //如果改item的天数的月份大于开始日期的月份,说明结束日期肯定大于开始日期 ,合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else if(dayTimeEntity.getMonth() == MonthTimeActivity.startDay.getMonth()){ //年份月份 都相等 if (dayTimeEntity.getDay() > = MonthTimeActivity.startDay.getDay()){ //判断天数 ,如果 该item的天数的 日子大于等于 开始日期的 日子 ,说明结束日期合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else{ //天数小与初始从新选择开始,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } }else { //选中的月份 比开始日期的月份还小,说明 结束位置不合法,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); }}else{ //选中的年份 比开始日期的年份还小,说明 结束位置不合法,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } }else if(MonthTimeActivity.startDay.getYear()> 0 & & MonthTimeActivity.startDay.getYear()> 1){//已经点击开始和结束第三次点击 ,重新点击开始 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } EventBus.getDefault().post(new UpdataCalendar()); // 发消息刷新适配器,目的为了显示日历上各个日期的背景颜色 } }); if (MonthTimeActivity.startDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.startDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.startDay.getDay() == dayTimeEntity.getDay() & & MonthTimeActivity.stopDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.stopDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.stopDay.getDay() == dayTimeEntity.getDay() ){ //开始和结束同一天 holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_startstop); } else if (MonthTimeActivity.startDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.startDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.startDay.getDay() == dayTimeEntity.getDay()){ //该item是 开始日期 holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_start); }else if(MonthTimeActivity.stopDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.stopDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.stopDay.getDay() == dayTimeEntity.getDay()){ //该item是 结束日期 holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_stop); }else if(dayTimeEntity.getMonthPosition()> = MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getMonthPosition()< = MonthTimeActivity.stopDay.getMonthPosition()){ //处于开始和结束之间的点 if (dayTimeEntity.getMonthPosition()== MonthTimeActivity.startDay.getMonthPosition()& & dayTimeEntity.getMonthPosition()== MonthTimeActivity.stopDay.getMonthPosition()){ //开始和结束是一个月份 if (dayTimeEntity.getDay()> MonthTimeActivity.startDay.getDay() & & dayTimeEntity.getDay() < MonthTimeActivity.stopDay.getDay()) { holder.select_ly_day.setBackgroundResource(R.color.blue); }else{ holder.select_ly_day.setBackgroundResource(R.color.white); } }else if(MonthTimeActivity.startDay.getMonthPosition() != MonthTimeActivity.stopDay.getMonthPosition()){ // 日期和 开始 不是一个月份 if (dayTimeEntity.getMonthPosition()== MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getDay()> MonthTimeActivity.startDay.getDay()){ //和初始相同月天数往后 holder.select_ly_day.setBackgroundResource(R.color.blue); }else if(dayTimeEntity.getMonthPosition()== MonthTimeActivity.stopDay.getMonthPosition() & & dayTimeEntity.getDay()< MonthTimeActivity.stopDay.getDay()){ //和结束相同月天数往前 holder.select_ly_day.setBackgroundResource(R.color.blue); }else if(dayTimeEntity.getMonthPosition()!= MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getMonthPosition()!= MonthTimeActivity.stopDay.getMonthPosition()){ //和 开始结束都不是同一个月 holder.select_ly_day.setBackgroundResource(R.color.blue); }else{ holder.select_ly_day.setBackgroundResource(R.color.white); } }}else{ holder.select_ly_day.setBackgroundResource(R.color.white); }}@Override public int getItemCount() { int ret = 0; if (days!=null){ ret = days.size(); } return ret; } }

DayTimeAdapter.java 
核心代码:
1、 不是日期的item不可点击,即 getDay()的到参数 为0的不可点击,详情看(5) 
//显示日期 if (dayTimeEntity.getDay()!=0) { holder.select_txt_day.setText(dayTimeEntity.getDay() + ""); holder.select_ly_day.setEnabled(true); }else{ holder.select_ly_day.setEnabled(false); }

 
  2、 item设置点击监听事件,标记并赋值“开始位置”和“结束位置”
holder.select_ly_day.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (MonthTimeActivity.startDay.getYear() == 0 ){// 第一次点击开始的位置,因为开始默认参数是 0,0,0,0 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); // 该item 天数的 年月日等信息赋给开始日期 MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); }else if(MonthTimeActivity.startDay.getYear()> 0 & & MonthTimeActivity.stopDay.getYear() ==-1){//已经点击了开始 ,点击结束位置,(默认结束位置-1,-1,-1,-1 说明还没有点击结束位置) if (dayTimeEntity.getYear()> MonthTimeActivity.startDay.getYear()) { //如果选中的年份大于开始的年份,说明结束日期肯定大于开始日期 ,合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else if (dayTimeEntity.getYear() == MonthTimeActivity.startDay.getYear()){ //如果选中的年份 等于 选中的年份 if (dayTimeEntity.getMonth()> MonthTimeActivity.startDay.getMonth()){ //如果改item的天数的月份大于开始日期的月份,说明结束日期肯定大于开始日期 ,合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else if(dayTimeEntity.getMonth() == MonthTimeActivity.startDay.getMonth()){ //年份月份 都相等 if (dayTimeEntity.getDay() > = MonthTimeActivity.startDay.getDay()){ //判断天数 ,如果 该item的天数的 日子大于等于 开始日期的 日子 ,说明结束日期合法的 ,将该item的天数的 信息赋给 结束日期 MonthTimeActivity.stopDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.stopDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.stopDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.stopDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.stopDay.setDayPosition(position); }else{ //天数小与初始从新选择开始,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } }else { //选中的月份 比开始日期的月份还小,说明 结束位置不合法,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); }}else{ //选中的年份 比开始日期的年份还小,说明 结束位置不合法,结束日期重置,开始日期为当前的位置的天数的信息 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } }else if(MonthTimeActivity.startDay.getYear()> 0 & & MonthTimeActivity.startDay.getYear()> 1){//已经点击开始和结束第三次点击 ,重新点击开始 MonthTimeActivity.startDay.setDay(dayTimeEntity.getDay()); MonthTimeActivity.startDay.setMonth(dayTimeEntity.getMonth()); MonthTimeActivity.startDay.setYear(dayTimeEntity.getYear()); MonthTimeActivity.startDay.setMonthPosition(dayTimeEntity.getMonthPosition()); MonthTimeActivity.startDay.setDayPosition(position); MonthTimeActivity.stopDay.setDay(-1); MonthTimeActivity.stopDay.setMonth(-1); MonthTimeActivity.stopDay.setYear(-1); MonthTimeActivity.stopDay.setMonthPosition(-1); MonthTimeActivity.stopDay.setDayPosition(-1); } EventBus.getDefault().post(new UpdataCalendar()); // 发消息刷新适配器,目的为了显示日历上各个日期的背景颜色 } });

3、根据每个item的年月日,在外部列表中的位置,在内部列表中的位置 信息 和“开始日期”、“结束日期”的信息对比,设置相应的背景色
if (MonthTimeActivity.startDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.startDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.startDay.getDay() == dayTimeEntity.getDay()
& & MonthTimeActivity.stopDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.stopDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.stopDay.getDay() == dayTimeEntity.getDay() ){
//开始和结束同一天
holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_startstop);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}
else if (MonthTimeActivity.startDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.startDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.startDay.getDay() == dayTimeEntity.getDay()){
//该item是 开始日期
holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_start);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}else if(MonthTimeActivity.stopDay.getYear()== dayTimeEntity.getYear() & & MonthTimeActivity.stopDay.getMonth() == dayTimeEntity.getMonth() & & MonthTimeActivity.stopDay.getDay() == dayTimeEntity.getDay()){
//该item是 结束日期
holder.select_ly_day.setBackgroundResource(R.drawable.bg_time_stop);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}else if(dayTimeEntity.getMonthPosition()> = MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getMonthPosition()< = MonthTimeActivity.stopDay.getMonthPosition()){
//处于开始和结束之间的点
if (dayTimeEntity.getMonthPosition()== MonthTimeActivity.startDay.getMonthPosition()& & dayTimeEntity.getMonthPosition()== MonthTimeActivity.stopDay.getMonthPosition()){
//开始和结束是一个月份
if (dayTimeEntity.getDay()> MonthTimeActivity.startDay.getDay() & & dayTimeEntity.getDay() < MonthTimeActivity.stopDay.getDay()) {
holder.select_ly_day.setBackgroundResource(R.color.blue);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}else{
holder.select_ly_day.setBackgroundResource(R.color.white);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.txtColor));
}
}else if(MonthTimeActivity.startDay.getMonthPosition() != MonthTimeActivity.stopDay.getMonthPosition()){
// 日期和 开始 不是一个月份
if (dayTimeEntity.getMonthPosition()== MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getDay()> MonthTimeActivity.startDay.getDay()){
//和初始相同月天数往后
holder.select_ly_day.setBackgroundResource(R.color.blue);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}else if(dayTimeEntity.getMonthPosition()== MonthTimeActivity.stopDay.getMonthPosition() & & dayTimeEntity.getDay()< MonthTimeActivity.stopDay.getDay()){
//和结束相同月天数往前
if (dayTimeEntity.getDay()< =0){
holder.select_ly_day.setBackgroundResource(R.color.white);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.txtColor));
}else {
holder.select_ly_day.setBackgroundResource(R.color.blue);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}
}else if(dayTimeEntity.getMonthPosition()!= MonthTimeActivity.startDay.getMonthPosition() & & dayTimeEntity.getMonthPosition()!= MonthTimeActivity.stopDay.getMonthPosition()){
//和 开始结束都不是同一个月
holder.select_ly_day.setBackgroundResource(R.color.blue);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.white));
}else{
holder.select_ly_day.setBackgroundResource(R.color.white);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.txtColor));
}
}

}else{
holder.select_ly_day.setBackgroundResource(R.color.white);
holder.select_txt_day.setTextColor(context.getResources().getColor(R.color.txtColor));
}

判断逻辑都在代码中有注释
(9) 资源文件的代码
1、drawable文件
bg_time_start.xml
< ?xml version="1.0" encoding="utf-8"?> < shape xmlns:android="http://schemas.android.com/apk/res/android"> < !--开始日期的背景--> < corners android:bottomLeftRadius="20dp" android:topLeftRadius="20dp" > < /corners> < solid android:color="#4ab7e8"> < /solid> < /shape>

bg_time_stop.xml
< ?xml version="1.0" encoding="utf-8"?> < shape xmlns:android="http://schemas.android.com/apk/res/android"> < !--结束日期的背景--> < corners android:bottomRightRadius="20dp" android:topRightRadius="20dp" > < /corners> < solid android:color="#4ab7e8"> < /solid> < /shape>

bg_time_startstop.xml
< ?xml version="1.0" encoding="utf-8"?> < shape xmlns:android="http://schemas.android.com/apk/res/android"> < !--开始日期和结束日期同一天的背景--> < corners android:radius="20dp" > < /corners> < solid android:color="#4ab7e8"> < /solid> < /shape>

(2)、colors.xml
< color name="white"> #fff< /color> < color name="blue"> #4ab7e8< /color>

 
 
【Android项目实战(二十九)(酒店预定日期选择)】--------------------------------------------------------------------------------------------------------------------------
GitHub:仿美团酒店预订日期选择

 
另:强制当天作为开始日期,只选择结束日期,可以调整结束日期和开始日期的间隔时间限制
GitHub: 仿美团酒店预订日期选择(强制当天作为开始日期)
 

























































    推荐阅读