先看需求效果图:

            

几个需求点:

1、显示当月以及下个月的日历 (可自行拓展更多月份)

2、首次点击选择“开始日期”,再次点击选择"结束日期"

  (1)、如果“开始日期” “结束日期” 相同 

  (2)、如果“开始日期” “结束日期” 不同,且“结束日期” 晚于 “开始日期” 

  (3)、如果“结束日期” 早于 “开始日期” ,重置当前 日期 为 “开始日期”

3、选择的“开始日期” “结束日期” 显示在 

难点:

1、 获取当月以及下个月的日历,一个月多少天,每天星期几

2、 判断每个日子的点 与  “开始日期” “结束日期” 的关系,用于显示背景色

技术储备:

1、浅谈RecyclerView(完美替代ListView,GridView)

2、Android项目实战(十三):浅谈EventBus

-----------------------------------------------------------------------------------------------------------------------

实现思路:

1、一个外部RecyclerView 用于显示 日历,每一个item 都用于显示一个月的日历             ,下面都称为 外部RecyclerView

2、外部RecyclerView的每一个Item 内再用一个RecyclerView显示该月的所有日期,每一天都是一个item   ,下面都称为 内部RecyclerView

3、点击内部RecyclerView的item 日期,添加监听事件,根据是否开始、结束、中间日期来显示 相应的选中背景

代码实现:

1、代码框架总览

2、实体类

(1)、月份类,外部RecyclerView的数据源实体类

/**
* 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的数据源实体类

/**
* 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)、更新类,用于选择 “开始日期”、“结束日期”之后的刷新适配器操作

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

UpdataCalendar.java

3、主要实现

(1)、主界面布局

上面就是普通的布局形式,日历用一个RecyclerView显示,这个列表的每一个item都用于显示一个月份的所有天数

<?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=""
android:text="S"
android:gravity="center"
/> <TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:text="M"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:text="T"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:text="W"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:text="T"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:text="F"
android:gravity="center" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
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

(2)、日历外部RecyclerView的ViewHolder类,可以看出外层RecyclerView 的 item 只需要一个TextView显示几年几月 和 一个RecyclerView显示该月的天数即可

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,
, // 每行显示item项数目
GridLayoutManager.VERTICAL, //水平排列
false
); plan_time_recycler_content.setLayoutManager(layoutManager);
}
}

MonthTimeViewHolder

(3)、日历外部RecyclerView的item 布局文件

<?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

(4)、Activity

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(,,,);
stopDay = new DayTimeEntity(-,-,-,-);
datas = new ArrayList<>(); Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+; c.add(Calendar.MONTH,);
int nextYear = c.get(Calendar.YEAR);
int nextMonth = c.get(Calendar.MONTH)+; 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() == -) {
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(,,,);
stopDay = new DayTimeEntity(-,-,-,-); //注意这里参数都为 -1 不是随便设的 ,后面会用到
datas = new ArrayList<>();
    
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+; // 获得当前月份的信息, 属于哪一年,哪一月 c.add(Calendar.MONTH,);
int nextYear = c.get(Calendar.YEAR);
int nextMonth = c.get(Calendar.MONTH)+; // 获得当前月份的下一个月份的信息, 属于哪一年,哪一月。 可以以此类推 不限制于 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

/**
* 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() - ); //指定月份 Java月份从0开始算
calendar.set(Calendar.DAY_OF_MONTH,); // 指定天数 ,这三行是为了得到 这一年这一月的第一天 int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); //得到该月份第一天 是星期几
ArrayList<DayTimeEntity> days = new ArrayList<DayTimeEntity>();
for (int i = ; i < dayOfWeek-; i++) { //
days.add(new DayTimeEntity(, monthTimeEntity.getMonth(), monthTimeEntity.getYear(),position));
}
calendar.add(Calendar.MONTH, );// 加一个月,变为下月的1号
calendar.add(Calendar.DATE, -);// 减去一天,变为当月最后一天
for (int i = ; 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 = ;
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 ,用于显示 几号

<?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

**
* Created by xqx on //.
*
*/
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

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()!=) {
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
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()> && MonthTimeActivity.stopDay.getYear() ==-){ //已经点击了开始 ,点击结束位置,(默认结束位置-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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
}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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
} }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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
}else if(MonthTimeActivity.startDay.getYear()> && MonthTimeActivity.startDay.getYear()>){ //已经点击开始和结束 第三次点击 ,重新点击开始
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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
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 = ;
if (days!=null){
ret = days.size();
}
return ret;
}
}

DayTimeAdapter.java

  核心代码:

  1、 不是日期的item不可点击,即 getDay()的到参数 为0的不可点击,详情看(5)

     //显示日期
if (dayTimeEntity.getDay()!=) {
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
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()> && MonthTimeActivity.stopDay.getYear() ==-){ //已经点击了开始 ,点击结束位置,(默认结束位置-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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
}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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
} }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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
}else if(MonthTimeActivity.startDay.getYear()> && MonthTimeActivity.startDay.getYear()>){ //已经点击开始和结束 第三次点击 ,重新点击开始
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(-);
MonthTimeActivity.stopDay.setMonth(-);
MonthTimeActivity.stopDay.setYear(-);
MonthTimeActivity.stopDay.setMonthPosition(-);
MonthTimeActivity.stopDay.setDayPosition(-);
}
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>

--------------------------------------------------------------------------------------------------------------------------

GitHub:仿美团酒店预订日期选择

另:强制当天作为开始日期,只选择结束日期,可以调整结束日期和开始日期的间隔时间限制

GitHub:仿美团酒店预订日期选择(强制当天作为开始日期)

Android项目实战(二十九):酒店预定日期选择的更多相关文章

  1. Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator

    Android Studio 优秀插件系列: Android Studio 优秀插件(一):GsonFormat Android Studio 优秀插件(二): Parcelable Code Gen ...

  2. Android项目实战(十二):解决OOM的一种偷懒又有效的办法

    在程序的manifest文件的application节点加入android:largeHeap=“true” 即可. 对,只需要一句话! 那么这行代码的意思是什么呢? 简单的说就是使该APP获取最大可 ...

  3. Java并发编程原理与实战二十九:Exchanger

    一.简介 前面三篇博客分别介绍了CyclicBarrier.CountDownLatch.Semaphore,现在介绍并发工具类中的最后一个Exchange.Exchange是最简单的也是最复杂的,简 ...

  4. Android开发(二十九)——layout_weight的含义

    首先声明只有在Linearlayout中,该属性才有效.之所以android:layout_weight会引起争议,是因为在设置该属性的同时,设置android:layout_width为wrap_c ...

  5. Android项目实战(十六):QQ空间实现(一)—— 展示说说中的评论内容并有相应点击事件

    大家都玩QQ空间客户端,对于每一个说说,我们都可以评论,那么,对于某一条评论: 白雪公主 回复 小矮人 : 你们好啊~ 我们来分析一下: .QQ空间允许我们 点击 回复人和被回复人的名字就可以进入对于 ...

  6. Android项目实战(十四):TextView显示html样式的文字

    项目需求: TextView显示一段文字,格式为:(消息个数,不确定)条消息 这段文字中名字和数字的长度是不确定的,还要求名字和数字各自有各自的颜色. 一开始我想的是用(转) SpannableStr ...

  7. Android项目实战(十):自定义倒计时的TextView

    项目总结 -------------------------------------------------------------------------------------------- 有这 ...

  8. kubernetes实战(二十九):Kubernetes RBAC实现不同用户在不同Namespace的不同权限

    1.基本说明 在生产环境使用k8s以后,大部分应用都实现了高可用,不仅降低了维护成本,也简化了很多应用的部署成本,但是同时也带来了诸多问题.比如开发可能需要查看自己的应用状态.连接信息.日志.执行命令 ...

  9. 应用程序框架实战二十九:Util Demo介绍

    上文介绍了我选择EasyUi作为前端框架的原因,并发放了最新Demo.本文将对这个Demo进行一些介绍,以方便你能够顺利运行起来. 这个Demo运行起来以后,是EasyUi的一个简单CRUD操作,数据 ...

随机推荐

  1. android缓存之Lrucache 和LinkedHashMap

    两者的区别 网上有很多人使用软引用加载图片的多 ,但是现在已经不再推荐使用这种方式了,(1)因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的 ...

  2. 使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍

    使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍 Windows MobileMobileWindowsMicrosoftWinForm 介绍 Microso ...

  3. background系列属性

    1.background-color背景颜色属性 ①颜色表示方法 英语单词:red   blue   purple    skyblue. rgb:r代表红色   g代表绿色   b代表蓝色    也 ...

  4. PHP处理多表查询时的SQL语句拆分与重新组装

    在自己写框架时候会发现,多表查询组装SQL语句<?php $pre = "pre_"; $aid = "44"; $data = array(" ...

  5. Windows Azure Table Storage 解决 Guid 查询问题

    在使用 Windows Azure Table Storage 的 CloudTableClient 对Azure 进行数据查询时,会发现在自定义类的Guid类型始终无法去成功查询出数据,对比发现 G ...

  6. UIStepper 缩放:UI的使用

    // 实现文件:声明在对应的.h文件.继承至UIViewControllor - (void)viewDidLoad { [super viewDidLoad]; // 按钮 self.stp = [ ...

  7. 用saxon框架对xml数据进行过滤 - 程序员的天堂 - ITeye技术网站

    用saxon框架对xml数据进行过滤 博客分类: Java   Saxon 是一个 XSLT 和XQuery处理器.它是使用 XML 文档和样式表作为输入,然后生成结果文档作为输出的程序,它还包括了一 ...

  8. Big Data架构师技能图谱

    大数据通用处理平台 Spark Flink Hadoop 分布式存储 HDFS 资源调度 Yarn Mesos 机器学习工具 Mahout Spark Mlib TensorFlow (Google ...

  9. (简单) POJ 1502 MPI Maelstrom,Dijkstra。

    Description BIT has recently taken delivery of their new supercomputer, a 32 processor Apollo Odysse ...

  10. Android与JNI(三) ---- c++调用java(转载)

    源码下载:JniDemo JNI就是Java Native Interface, 即可以实现Java调用本地库, 也可以实现C/C++调用Java代码, 从而实现了两种语言的互通, 可以让我们更加灵活 ...