开发中碰到个需求,需要在一个控件中选择完成开始和结束日期。实现的过程走的是程序员开发的老路子,找到轮子后自己改吧改吧就成了。去年做的找不到参考的文章连接了,请原博主见谅。
当时做的时候有几个需求:1.当天为最大的结束日期,2.最大选择范围1年,3.开始时间和结束时间可以为同一天。如有其他需求实现,可以参考代码改进一下。先上效果图:
视频点击后的虚影是屏幕录制的原因。实现步骤:(如有缺失什么资源,请告知。开始时间和结束时间显示自己布局内添加就可以)
1.自定义控件属性
<declare-styleable name="MyCalendar">
<attr name="dateformat" format="string"></attr>
<attr name="titleSize" format="dimension"></attr>
<attr name="titleColor" format="color"></attr>
<attr name="goIcon" format="reference"></attr>
<attr name="preIcon" format="reference"></attr>
<attr name="dayInMonthColor" format="color"></attr>
<attr name="dayOutMonthcolor" format="color"></attr>
<attr name="todayColor" format="color"></attr>
<attr name="todayEmptycircleColor" format="color"></attr>
<attr name="todayFillcircleColor" format="color"></attr>
<attr name="calendarbackground" format="color|reference"></attr>
</declare-styleable>
2.自定义控件代码
/**
* @Description: 可以选择时间范围的日历控件
* @Author MengXY
* @Emil mxy_2012_1@163.com
* @Date 2019/1/8
*/
public class CalendarView extends LinearLayout implements View.OnClickListener{
private TextView title;
private RecyclerView recyclerView;
private RelativeLayout layout_calendar_gonext;
private RelativeLayout layout_calendar_goup;
private LinearLayoutManager linearLayoutManager;
private Calendar curDate = Calendar.getInstance();
//从服务器获取的日期
private Date dateFromServer;
//外层主recyclerview的adapter
private MainRvAdapter mainAdapter;
private List<CalendarCell> months = new ArrayList<>();
private Context context;
//相关属性
private int titleColor;
private int titleSize;
private int enableSelectColor;
private int disableSeletColor;
private int todayColor;
private int todayEmptyColor;
private int todayFillColor;
/** 初始日期为当前日期前一年*/
private String time;
private long timeBefor;
private long timeNow;
private List<String> titles = new ArrayList<>();
//点击的开始时间与结束时间
private Date sDateTime;
private Date eDateTime;
private boolean isSelectingSTime = true;
private HashMap<Integer, SubRvAdapter> allAdapters = new HashMap<>();
public CalendarView(Context context) {
this(context, null);
}
public CalendarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
private int maxSelect = 13;
public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCalendar);
titleColor = ta.getColor(R.styleable.MyCalendar_titleColor, Color.WHITE);
titleSize = (int) ta.getDimension(R.styleable.MyCalendar_titleSize, 15);
enableSelectColor = ta.getColor(R.styleable.MyCalendar_dayInMonthColor, context.getResources().getColor(R.color.text_lable));
disableSeletColor = ta.getColor(R.styleable.MyCalendar_dayOutMonthcolor, context.getResources().getColor(R.color.text_unenable));
todayColor = ta.getColor(R.styleable.MyCalendar_todayColor, Color.BLUE);
todayEmptyColor = ta.getColor(R.styleable.MyCalendar_todayEmptycircleColor, Color.CYAN);
todayFillColor = ta.getColor(R.styleable.MyCalendar_todayFillcircleColor, Color.CYAN);
ta.recycle();
this.context = context;
init(context);
}
//该方法用于设置从服务器获取的时间,如果没有从服务器获取的时间将使用手机本地时间
private void initTime() {
Calendar calendar = Calendar.getInstance(); //得到日历
calendar.setTime(new Date());
calendar.add(Calendar.MONTH,-(maxSelect-1));
time = DateUtils.formatData(calendar.getTime(),Constant.TFORMATE_YMD);
timeBefor = DateUtils.getDataTime(time);
String now = DateUtils.formatData(new Date(),Constant.TFORMATE_YMD);
timeNow = DateUtils.getDataTime(now);
// LogUtils.e("之前日期:"+time+"=="+timeBefor);
// LogUtils.e("当前日期:"+now+"=="+timeNow);
curDate = DateUtil.strToCalendar(time, Constant.TFORMATE_YMD);
dateFromServer = DateUtil.strToDate(time, Constant.TFORMATE_YMD);
}
private void init(Context context) {
bindView(context);
renderCalendar();
}
private void bindView(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.appoint_calendarview, this, false);
title = (TextView) view.findViewById(R.id.calendar_title);
title.setTextColor(titleColor);
title.setTextSize(titleSize);
layout_calendar_gonext = view.findViewById(R.id.layout_calendar_gonext);
layout_calendar_goup = view.findViewById(R.id.layout_calendar_goup);
layout_calendar_gonext.setOnClickListener(this);
layout_calendar_goup.setOnClickListener(this);
recyclerView = (RecyclerView) view.findViewById(R.id.calendar_rv);
linearLayoutManager = new LinearLayoutManager(this.context, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
addView(view);
}
public void renderCalendar() {
months.clear();
initTime();
for (int i = 0; i < maxSelect; i++) {
ArrayList<Date> cells = new ArrayList<>();
if (i != 0) {
curDate.add(Calendar.MONTH, 1);//后推一个月
} else {
curDate.add(Calendar.MONTH, 0);//当前月
}
Calendar calendar = (Calendar) curDate.clone();
//将日历设置到当月第一天
calendar.set(Calendar.DAY_OF_MONTH, 1);
//获得当月第一天是星期几,如果是星期一则返回1此时1-1=0证明上个月没有多余天数
int prevDays = calendar.get(Calendar.DAY_OF_WEEK) - 1;
//将calendar在1号的基础上向前推prevdays天。
calendar.add(Calendar.DAY_OF_MONTH, -prevDays);
//最大行数是6*7也就是,1号正好是星期六时的情况
int maxCellcount = 6 * 7;
while (cells.size() < maxCellcount) {
cells.add(calendar.getTime());
//日期后移一天
calendar.add(calendar.DAY_OF_MONTH, 1);
}
months.add(new CalendarCell(i, cells));
}
for (int i = 0; i < months.size(); i++) {
//title格式 2018年6月3日
String title = (months.get(i).getCells().get(20).getYear() + 1900) +
"\t-\t" +
(months.get(i).getCells().get(20).getMonth() + 1);
titles.add(title);
}
title.setText(titles.get(maxSelect-1));
//只限定3个月,因此模拟给3个数值即可
mainAdapter = new MainRvAdapter(R.layout.appoint_calendarview_item, months);
recyclerView.setAdapter(mainAdapter);
//recyclerview 的滚动监听
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
title.setText(titles.get(linearLayoutManager.findLastVisibleItemPosition()));
super.onScrollStateChanged(recyclerView, newState);
}
});
recyclerView.scrollToPosition(maxSelect-1);
}
@Override
public void onClick(View v) {
int index = linearLayoutManager.findLastVisibleItemPosition();
LogUtils.e("当前项"+index);
switch (v.getId()){
case R.id.layout_calendar_gonext:
if(index < maxSelect-1){
recyclerView.scrollToPosition(index+1);
title.setText(titles.get(index+1));
}
break;
case R.id.layout_calendar_goup:
if(index > 0){
recyclerView.scrollToPosition(index-1);
title.setText(titles.get(index-1));
}
break;
}
}
/**
* 最外层水平recyclerview的adapter
*/
private class MainRvAdapter extends BaseQuickAdapter<CalendarCell, BaseViewHolder> {
public MainRvAdapter(int layoutResId, @Nullable List<CalendarCell> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, final CalendarCell item) {
if (((RecyclerView) helper.getView(R.id.appoint_calendarview_item_rv)).getLayoutManager() == null) {
//RecyclerView不能都使用同一个LayoutManager
GridLayoutManager manager = new GridLayoutManager(mContext, 7);
//recyclerview嵌套高度不固定(wrap_content)时必须setAutoMeasureEnabled(true),否则测量时控件高度为0
manager.setAutoMeasureEnabled(true);
((RecyclerView) helper.getView(R.id.appoint_calendarview_item_rv)).setLayoutManager(manager);
}
SubRvAdapter subRvAdapter = null;
if (allAdapters.get(helper.getPosition()) == null) {
subRvAdapter = new SubRvAdapter(R.layout.calendar_text_day, item.getCells());
allAdapters.put