设计思想来源于Web界面在移动端的日期控件。
效果图
单个日期选择:
日期区段选择:
属性配置
<declare-styleable name="MyCalendar">
<!--标头文字-->
<attr name="titleTip" format="string"></attr>
<!--选择单个/范围日期-->
<attr name="mode" format="integer">
<enum name="date" value="0"></enum>
<enum name="range" value="1"></enum>
</attr>
<!--开始日期-->
<attr name="startDate" format="string"></attr>
<!--结束日期-->
<attr name="endDate" format="string"></attr>
<!--可选最小日期-->
<attr name="minDate" format="string"></attr>
<!--可选最大日期-->
<attr name="maxDate" format="string"></attr>
<!--选中的背景颜色-->
<attr name="selectColor" format="reference"></attr>
<!--背景颜色-->
<attr name="backgroundColor" format="reference"></attr>
<!--文字基础颜色-->
<attr name="nomorCollor" format="reference"></attr>
<!--区间模式背景颜色-->
<attr name="dateSectionColor" format="reference"></attr>
<!--标题文字大小-->
<attr name="titleTextSize" format="dimension"></attr>
<!--日期字体大小-->
<attr name="dayTextSize" format="dimension"></attr>
<!--底部描述文字大小-->
<attr name="tipTextSize" format="dimension"></attr>
<!--开始时间底部描述 mode为range模式生效-->
<attr name="startDateTip" format="string"></attr>
<!--结束时间底部描述 mode为range模式生效-->
<attr name="endDateTip" format="string"></attr>
</declare-styleable>
实现思路
关键步骤
- 计算某一年,某一月有多少天,1号位于星期几。
float days = new Date(year, month, 0).getDate(); //这个月多少天
//格布局为 周日 周 一 周二 周三 周四 周五 周六
int space = new Date(year, month - 1, 1).getDay(); //在第几个格 0代表周六
- 操作区域的平行,旋转转换与缓存,重写onTouchEvent事件,区分点击操作还是选择日期。
- 重写onMeasure,当日期由五行切换为六行(当月1号为星期六的情况下)显示时,使控件自动适应。
float days = new Date(year, month, 0).getDate();
int space = new Date(year, month - 1, 1).getDay();
float residueDays = days; //剩余的天数
if (space == 0) {
residueDays = residueDays - 1;
} else {
residueDays = residueDays - (7 - space) - 1;
}
currentLine = (int) Math.ceil(residueDays / 7) + 1;
int heightSpec = clientHight / 2;
int result = currentLine == 5 ? heightSpec : (int) (heightSpec + heightSpec * (0.44 - 0.3));
heightMeasureSpec =MeasureSpec.makeMeasureSpec(result,MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
代码较多,提供demo地址。有需要的小伙伴可自行查看。