android 自定义日历控件

时间:2021-08-25 21:22:06

android 自定义日历控件

日历控件View:

  1. /**
  2. * 日历控件 功能:获得点选的日期区间
  3. *
  4. */
  5. public class CalendarView extends View implements View.OnTouchListener {
  6. private final static String TAG = "anCalendar";
  7. private Date selectedStartDate;
  8. private Date selectedEndDate;
  9. private Date curDate; // 当前日历显示的月
  10. private Date today; // 今天的日期文字显示红色
  11. private Date downDate; // 手指按下状态时临时日期
  12. private Date showFirstDate, showLastDate; // 日历显示的第一个日期和最后一个日期
  13. private int downIndex; // 按下的格子索引
  14. private Calendar calendar;
  15. private Surface surface;
  16. private int[] date = new int[42]; // 日历显示数字
  17. private int curStartIndex, curEndIndex; // 当前显示的日历起始的索引
  18. //private boolean completed = false; // 为false表示只选择了开始日期,true表示结束日期也选择了
  19. //给控件设置监听事件
  20. private OnItemClickListener onItemClickListener;
  21. public CalendarView(Context context) {
  22. super(context);
  23. init();
  24. }
  25. public CalendarView(Context context, AttributeSet attrs) {
  26. super(context, attrs);
  27. init();
  28. }
  29. private void init() {
  30. curDate = selectedStartDate = selectedEndDate = today = new Date();
  31. calendar = Calendar.getInstance();
  32. calendar.setTime(curDate);
  33. surface = new Surface();
  34. surface.density = getResources().getDisplayMetrics().density;
  35. setBackgroundColor(surface.bgColor);
  36. setOnTouchListener(this);
  37. }
  38. @Override
  39. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  40. surface.width = getResources().getDisplayMetrics().widthPixels;
  41. surface.height = (int) (getResources().getDisplayMetrics().heightPixels*2/5);
  42. //      if (View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY) {
  43. //          surface.width = View.MeasureSpec.getSize(widthMeasureSpec);
  44. //      }
  45. //      if (View.MeasureSpec.getMode(heightMeasureSpec) == View.MeasureSpec.EXACTLY) {
  46. //          surface.height = View.MeasureSpec.getSize(heightMeasureSpec);
  47. //      }
  48. widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.width,
  49. View.MeasureSpec.EXACTLY);
  50. heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.height,
  51. View.MeasureSpec.EXACTLY);
  52. setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
  53. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  54. }
  55. @Override
  56. protected void onLayout(boolean changed, int left, int top, int right,
  57. int bottom) {
  58. Log.d(TAG, "[onLayout] changed:"
  59. + (changed ? "new size" : "not change") + " left:" + left
  60. + " top:" + top + " right:" + right + " bottom:" + bottom);
  61. if (changed) {
  62. surface.init();
  63. }
  64. super.onLayout(changed, left, top, right, bottom);
  65. }
  66. @Override
  67. protected void onDraw(Canvas canvas) {
  68. Log.d(TAG, "onDraw");
  69. // 画框
  70. canvas.drawPath(surface.boxPath, surface.borderPaint);
  71. // 年月
  72. //String monthText = getYearAndmonth();
  73. //float textWidth = surface.monthPaint.measureText(monthText);
  74. //canvas.drawText(monthText, (surface.width - textWidth) / 2f,
  75. //      surface.monthHeight * 3 / 4f, surface.monthPaint);
  76. // 上一月/下一月
  77. //canvas.drawPath(surface.preMonthBtnPath, surface.monthChangeBtnPaint);
  78. //canvas.drawPath(surface.nextMonthBtnPath, surface.monthChangeBtnPaint);
  79. // 星期
  80. float weekTextY = surface.monthHeight + surface.weekHeight * 3 / 4f;
  81. // 星期背景
  82. //      surface.cellBgPaint.setColor(surface.textColor);
  83. //      canvas.drawRect(surface.weekHeight, surface.width, surface.weekHeight, surface.width, surface.cellBgPaint);
  84. for (int i = 0; i < surface.weekText.length; i++) {
  85. float weekTextX = i
  86. * surface.cellWidth
  87. + (surface.cellWidth - surface.weekPaint
  88. .measureText(surface.weekText[i])) / 2f;
  89. canvas.drawText(surface.weekText[i], weekTextX, weekTextY,
  90. surface.weekPaint);
  91. }
  92. // 计算日期
  93. calculateDate();
  94. // 按下状态,选择状态背景色
  95. drawDownOrSelectedBg(canvas);
  96. // write date number
  97. // today index
  98. int todayIndex = -1;
  99. calendar.setTime(curDate);
  100. String curYearAndMonth = calendar.get(Calendar.YEAR) + ""
  101. + calendar.get(Calendar.MONTH);
  102. calendar.setTime(today);
  103. String todayYearAndMonth = calendar.get(Calendar.YEAR) + ""
  104. + calendar.get(Calendar.MONTH);
  105. if (curYearAndMonth.equals(todayYearAndMonth)) {
  106. int todayNumber = calendar.get(Calendar.DAY_OF_MONTH);
  107. todayIndex = curStartIndex + todayNumber - 1;
  108. }
  109. for (int i = 0; i < 42; i++) {
  110. int color = surface.textColor;
  111. if (isLastMonth(i)) {
  112. color = surface.borderColor;
  113. } else if (isNextMonth(i)) {
  114. color = surface.borderColor;
  115. }
  116. if (todayIndex != -1 && i == todayIndex) {
  117. color = surface.todayNumberColor;
  118. }
  119. drawCellText(canvas, i, date[i] + "", color);
  120. }
  121. super.onDraw(canvas);
  122. }
  123. private void calculateDate() {
  124. calendar.setTime(curDate);
  125. calendar.set(Calendar.DAY_OF_MONTH, 1);
  126. int dayInWeek = calendar.get(Calendar.DAY_OF_WEEK);
  127. Log.d(TAG, "day in week:" + dayInWeek);
  128. int monthStart = dayInWeek;
  129. if (monthStart == 1) {
  130. monthStart = 8;
  131. }
  132. monthStart -= 1;  //以日为开头-1,以星期一为开头-2
  133. curStartIndex = monthStart;
  134. date[monthStart] = 1;
  135. // last month
  136. if (monthStart > 0) {
  137. calendar.set(Calendar.DAY_OF_MONTH, 0);
  138. int dayInmonth = calendar.get(Calendar.DAY_OF_MONTH);
  139. for (int i = monthStart - 1; i >= 0; i--) {
  140. date[i] = dayInmonth;
  141. dayInmonth--;
  142. }
  143. calendar.set(Calendar.DAY_OF_MONTH, date[0]);
  144. }
  145. showFirstDate = calendar.getTime();
  146. // this month
  147. calendar.setTime(curDate);
  148. calendar.add(Calendar.MONTH, 1);
  149. calendar.set(Calendar.DAY_OF_MONTH, 0);
  150. // Log.d(TAG, "m:" + calendar.get(Calendar.MONTH) + " d:" +
  151. // calendar.get(Calendar.DAY_OF_MONTH));
  152. int monthDay = calendar.get(Calendar.DAY_OF_MONTH);
  153. for (int i = 1; i < monthDay; i++) {
  154. date[monthStart + i] = i + 1;
  155. }
  156. curEndIndex = monthStart + monthDay;
  157. // next month
  158. for (int i = monthStart + monthDay; i < 42; i++) {
  159. date[i] = i - (monthStart + monthDay) + 1;
  160. }
  161. if (curEndIndex < 42) {
  162. // 显示了下一月的
  163. calendar.add(Calendar.DAY_OF_MONTH, 1);
  164. }
  165. calendar.set(Calendar.DAY_OF_MONTH, date[41]);
  166. showLastDate = calendar.getTime();
  167. }
  168. /**
  169. *
  170. * @param canvas
  171. * @param index
  172. * @param text
  173. */
  174. private void drawCellText(Canvas canvas, int index, String text, int color) {
  175. int x = getXByIndex(index);
  176. int y = getYByIndex(index);
  177. surface.datePaint.setColor(color);
  178. float cellY = surface.monthHeight + surface.weekHeight + (y - 1)
  179. * surface.cellHeight + surface.cellHeight * 3 / 4f;
  180. float cellX = (surface.cellWidth * (x - 1))
  181. + (surface.cellWidth - surface.datePaint.measureText(text))
  182. / 2f;
  183. canvas.drawText(text, cellX, cellY, surface.datePaint);
  184. }
  185. /**
  186. *
  187. * @param canvas
  188. * @param index
  189. * @param color
  190. */
  191. private void drawCellBg(Canvas canvas, int index, int color) {
  192. int x = getXByIndex(index);
  193. int y = getYByIndex(index);
  194. surface.cellBgPaint.setColor(color);
  195. float left = surface.cellWidth * (x - 1) + surface.borderWidth;
  196. float top = surface.monthHeight + surface.weekHeight + (y - 1)
  197. * surface.cellHeight + surface.borderWidth;
  198. canvas.drawRect(left, top, left + surface.cellWidth
  199. - surface.borderWidth, top + surface.cellHeight
  200. - surface.borderWidth, surface.cellBgPaint);
  201. }
  202. private void drawDownOrSelectedBg(Canvas canvas) {
  203. // down and not up
  204. if (downDate != null) {
  205. drawCellBg(canvas, downIndex, surface.cellDownColor);
  206. }
  207. // selected bg color
  208. if (!selectedEndDate.before(showFirstDate)
  209. && !selectedStartDate.after(showLastDate)) {
  210. int[] section = new int[] { -1, -1 };
  211. calendar.setTime(curDate);
  212. calendar.add(Calendar.MONTH, -1);
  213. findSelectedIndex(0, curStartIndex, calendar, section);
  214. if (section[1] == -1) {
  215. calendar.setTime(curDate);
  216. findSelectedIndex(curStartIndex, curEndIndex, calendar, section);
  217. }
  218. if (section[1] == -1) {
  219. calendar.setTime(curDate);
  220. calendar.add(Calendar.MONTH, 1);
  221. findSelectedIndex(curEndIndex, 42, calendar, section);
  222. }
  223. if (section[0] == -1) {
  224. section[0] = 0;
  225. }
  226. if (section[1] == -1) {
  227. section[1] = 41;
  228. }
  229. for (int i = section[0]; i <= section[1]; i++) {
  230. drawCellBg(canvas, i, surface.cellSelectedColor);
  231. }
  232. }
  233. }
  234. private void findSelectedIndex(int startIndex, int endIndex,
  235. Calendar calendar, int[] section) {
  236. for (int i = startIndex; i < endIndex; i++) {
  237. calendar.set(Calendar.DAY_OF_MONTH, date[i]);
  238. Date temp = calendar.getTime();
  239. // Log.d(TAG, "temp:" + temp.toLocaleString());
  240. if (temp.compareTo(selectedStartDate) == 0) {
  241. section[0] = i;
  242. }
  243. if (temp.compareTo(selectedEndDate) == 0) {
  244. section[1] = i;
  245. return;
  246. }
  247. }
  248. }
  249. public Date getSelectedStartDate() {
  250. return selectedStartDate;
  251. }
  252. public Date getSelectedEndDate() {
  253. return selectedEndDate;
  254. }
  255. private boolean isLastMonth(int i) {
  256. if (i < curStartIndex) {
  257. return true;
  258. }
  259. return false;
  260. }
  261. private boolean isNextMonth(int i) {
  262. if (i >= curEndIndex) {
  263. return true;
  264. }
  265. return false;
  266. }
  267. private int getXByIndex(int i) {
  268. return i % 7 + 1; // 1 2 3 4 5 6 7
  269. }
  270. private int getYByIndex(int i) {
  271. return i / 7 + 1; // 1 2 3 4 5 6
  272. }
  273. // 获得当前应该显示的年月
  274. public String getYearAndmonth() {
  275. calendar.setTime(curDate);
  276. int year = calendar.get(Calendar.YEAR);
  277. int month = calendar.get(Calendar.MONTH);
  278. return year + "-" + surface.monthText[month];
  279. }
  280. //上一月
  281. public String clickLeftMonth(){
  282. calendar.setTime(curDate);
  283. calendar.add(Calendar.MONTH, -1);
  284. curDate = calendar.getTime();
  285. invalidate();
  286. return getYearAndmonth();
  287. }
  288. //下一月
  289. public String clickRightMonth(){
  290. calendar.setTime(curDate);
  291. calendar.add(Calendar.MONTH, 1);
  292. curDate = calendar.getTime();
  293. invalidate();
  294. return getYearAndmonth();
  295. }
  296. private void setSelectedDateByCoor(float x, float y) {
  297. // change month
  298. //      if (y < surface.monthHeight) {
  299. //          // pre month
  300. //          if (x < surface.monthChangeWidth) {
  301. //              calendar.setTime(curDate);
  302. //              calendar.add(Calendar.MONTH, -1);
  303. //              curDate = calendar.getTime();
  304. //          }
  305. //          // next month
  306. //          else if (x > surface.width - surface.monthChangeWidth) {
  307. //              calendar.setTime(curDate);
  308. //              calendar.add(Calendar.MONTH, 1);
  309. //              curDate = calendar.getTime();
  310. //          }
  311. //      }
  312. // cell click down
  313. if (y > surface.monthHeight + surface.weekHeight) {
  314. int m = (int) (Math.floor(x / surface.cellWidth) + 1);
  315. int n = (int) (Math
  316. .floor((y - (surface.monthHeight + surface.weekHeight))
  317. / Float.valueOf(surface.cellHeight)) + 1);
  318. downIndex = (n - 1) * 7 + m - 1;
  319. Log.d(TAG, "downIndex:" + downIndex);
  320. calendar.setTime(curDate);
  321. if (isLastMonth(downIndex)) {
  322. calendar.add(Calendar.MONTH, -1);
  323. } else if (isNextMonth(downIndex)) {
  324. calendar.add(Calendar.MONTH, 1);
  325. }
  326. calendar.set(Calendar.DAY_OF_MONTH, date[downIndex]);
  327. downDate = calendar.getTime();
  328. }
  329. invalidate();
  330. }
  331. @Override
  332. public boolean onTouch(View v, MotionEvent event) {
  333. switch (event.getAction()) {
  334. case MotionEvent.ACTION_DOWN:
  335. setSelectedDateByCoor(event.getX(), event.getY());
  336. break;
  337. case MotionEvent.ACTION_UP:
  338. if (downDate != null) {
  339. //              if (!completed) {
  340. //                  if (downDate.before(selectedStartDate)) {
  341. //                      selectedEndDate = selectedStartDate;
  342. //                      selectedStartDate = downDate;
  343. //                  } else {
  344. //                      selectedEndDate = downDate;
  345. //                  }
  346. //                  completed = true;
  347. //              } else {
  348. //                  selectedStartDate = selectedEndDate = downDate;
  349. //                  completed = false;
  350. //              }
  351. selectedStartDate = selectedEndDate = downDate;
  352. //响应监听事件
  353. onItemClickListener.OnItemClick(selectedStartDate);
  354. // Log.d(TAG, "downdate:" + downDate.toLocaleString());
  355. //Log.d(TAG, "start:" + selectedStartDate.toLocaleString());
  356. //Log.d(TAG, "end:" + selectedEndDate.toLocaleString());
  357. downDate = null;
  358. invalidate();
  359. }
  360. break;
  361. }
  362. return true;
  363. }
  364. //给控件设置监听事件
  365. public void setOnItemClickListener(OnItemClickListener onItemClickListener){
  366. this.onItemClickListener =  onItemClickListener;
  367. }
  368. //监听接口
  369. public interface OnItemClickListener {
  370. void OnItemClick(Date date);
  371. }
  372. /**
  373. *
  374. * 1. 布局尺寸 2. 文字颜色,大小 3. 当前日期的颜色,选择的日期颜色
  375. */
  376. private class Surface {
  377. public float density;
  378. public int width; // 整个控件的宽度
  379. public int height; // 整个控件的高度
  380. public float monthHeight; // 显示月的高度
  381. //public float monthChangeWidth; // 上一月、下一月按钮宽度
  382. public float weekHeight; // 显示星期的高度
  383. public float cellWidth; // 日期方框宽度
  384. public float cellHeight; // 日期方框高度
  385. public float borderWidth;
  386. public int bgColor = Color.parseColor("#FFFFFF");
  387. private int textColor = Color.BLACK;
  388. //private int textColorUnimportant = Color.parseColor("#666666");
  389. private int btnColor = Color.parseColor("#666666");
  390. private int borderColor = Color.parseColor("#CCCCCC");
  391. public int todayNumberColor = Color.RED;
  392. public int cellDownColor = Color.parseColor("#CCFFFF");
  393. public int cellSelectedColor = Color.parseColor("#99CCFF");
  394. public Paint borderPaint;
  395. public Paint monthPaint;
  396. public Paint weekPaint;
  397. public Paint datePaint;
  398. public Paint monthChangeBtnPaint;
  399. public Paint cellBgPaint;
  400. public Path boxPath; // 边框路径
  401. //public Path preMonthBtnPath; // 上一月按钮三角形
  402. //public Path nextMonthBtnPath; // 下一月按钮三角形
  403. public String[] weekText = { "Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  404. public String[] monthText = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  405. public void init() {
  406. float temp = height / 7f;
  407. monthHeight = 0;//(float) ((temp + temp * 0.3f) * 0.6);
  408. //monthChangeWidth = monthHeight * 1.5f;
  409. weekHeight = (float) ((temp + temp * 0.3f) * 0.7);
  410. cellHeight = (height - monthHeight - weekHeight) / 6f;
  411. cellWidth = width / 7f;
  412. borderPaint = new Paint();
  413. borderPaint.setColor(borderColor);
  414. borderPaint.setStyle(Paint.Style.STROKE);
  415. borderWidth = (float) (0.5 * density);
  416. // Log.d(TAG, "borderwidth:" + borderWidth);
  417. borderWidth = borderWidth < 1 ? 1 : borderWidth;
  418. borderPaint.setStrokeWidth(borderWidth);
  419. monthPaint = new Paint();
  420. monthPaint.setColor(textColor);
  421. monthPaint.setAntiAlias(true);
  422. float textSize = cellHeight * 0.4f;
  423. Log.d(TAG, "text size:" + textSize);
  424. monthPaint.setTextSize(textSize);
  425. monthPaint.setTypeface(Typeface.DEFAULT_BOLD);
  426. weekPaint = new Paint();
  427. weekPaint.setColor(textColor);
  428. weekPaint.setAntiAlias(true);
  429. float weekTextSize = weekHeight * 0.6f;
  430. weekPaint.setTextSize(weekTextSize);
  431. weekPaint.setTypeface(Typeface.DEFAULT_BOLD);
  432. datePaint = new Paint();
  433. datePaint.setColor(textColor);
  434. datePaint.setAntiAlias(true);
  435. float cellTextSize = cellHeight * 0.5f;
  436. datePaint.setTextSize(cellTextSize);
  437. datePaint.setTypeface(Typeface.DEFAULT_BOLD);
  438. boxPath = new Path();
  439. //boxPath.addRect(0, 0, width, height, Direction.CW);
  440. //boxPath.moveTo(0, monthHeight);
  441. boxPath.rLineTo(width, 0);
  442. boxPath.moveTo(0, monthHeight + weekHeight);
  443. boxPath.rLineTo(width, 0);
  444. for (int i = 1; i < 6; i++) {
  445. boxPath.moveTo(0, monthHeight + weekHeight + i * cellHeight);
  446. boxPath.rLineTo(width, 0);
  447. boxPath.moveTo(i * cellWidth, monthHeight);
  448. boxPath.rLineTo(0, height - monthHeight);
  449. }
  450. boxPath.moveTo(6 * cellWidth, monthHeight);
  451. boxPath.rLineTo(0, height - monthHeight);
  452. //preMonthBtnPath = new Path();
  453. //int btnHeight = (int) (monthHeight * 0.6f);
  454. //preMonthBtnPath.moveTo(monthChangeWidth / 2f, monthHeight / 2f);
  455. //preMonthBtnPath.rLineTo(btnHeight / 2f, -btnHeight / 2f);
  456. //preMonthBtnPath.rLineTo(0, btnHeight);
  457. //preMonthBtnPath.close();
  458. //nextMonthBtnPath = new Path();
  459. //nextMonthBtnPath.moveTo(width - monthChangeWidth / 2f,
  460. //      monthHeight / 2f);
  461. //nextMonthBtnPath.rLineTo(-btnHeight / 2f, -btnHeight / 2f);
  462. //nextMonthBtnPath.rLineTo(0, btnHeight);
  463. //nextMonthBtnPath.close();
  464. monthChangeBtnPaint = new Paint();
  465. monthChangeBtnPaint.setAntiAlias(true);
  466. monthChangeBtnPaint.setStyle(Paint.Style.FILL_AND_STROKE);
  467. monthChangeBtnPaint.setColor(btnColor);
  468. cellBgPaint = new Paint();
  469. cellBgPaint.setAntiAlias(true);
  470. cellBgPaint.setStyle(Paint.Style.FILL);
  471. cellBgPaint.setColor(cellSelectedColor);
  472. }
  473. }
  474. }
/**
* 日历控件 功能:获得点选的日期区间
*
*/
public class CalendarView extends View implements View.OnTouchListener {
private final static String TAG = "anCalendar";
private Date selectedStartDate;
private Date selectedEndDate;
private Date curDate; // 当前日历显示的月
private Date today; // 今天的日期文字显示红色
private Date downDate; // 手指按下状态时临时日期
private Date showFirstDate, showLastDate; // 日历显示的第一个日期和最后一个日期
private int downIndex; // 按下的格子索引
private Calendar calendar;
private Surface surface;
private int[] date = new int[42]; // 日历显示数字
private int curStartIndex, curEndIndex; // 当前显示的日历起始的索引
//private boolean completed = false; // 为false表示只选择了开始日期,true表示结束日期也选择了
//给控件设置监听事件
private OnItemClickListener onItemClickListener; public CalendarView(Context context) {
super(context);
init();
} public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} private void init() {
curDate = selectedStartDate = selectedEndDate = today = new Date();
calendar = Calendar.getInstance();
calendar.setTime(curDate);
surface = new Surface();
surface.density = getResources().getDisplayMetrics().density;
setBackgroundColor(surface.bgColor);
setOnTouchListener(this);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
surface.width = getResources().getDisplayMetrics().widthPixels;
surface.height = (int) (getResources().getDisplayMetrics().heightPixels*2/5);
// if (View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY) {
// surface.width = View.MeasureSpec.getSize(widthMeasureSpec);
// }
// if (View.MeasureSpec.getMode(heightMeasureSpec) == View.MeasureSpec.EXACTLY) {
// surface.height = View.MeasureSpec.getSize(heightMeasureSpec);
// }
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.width,
View.MeasureSpec.EXACTLY);
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.height,
View.MeasureSpec.EXACTLY);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} @Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
Log.d(TAG, "[onLayout] changed:"
+ (changed ? "new size" : "not change") + " left:" + left
+ " top:" + top + " right:" + right + " bottom:" + bottom);
if (changed) {
surface.init();
}
super.onLayout(changed, left, top, right, bottom);
} @Override
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw");
// 画框
canvas.drawPath(surface.boxPath, surface.borderPaint);
// 年月
//String monthText = getYearAndmonth();
//float textWidth = surface.monthPaint.measureText(monthText);
//canvas.drawText(monthText, (surface.width - textWidth) / 2f,
// surface.monthHeight * 3 / 4f, surface.monthPaint);
// 上一月/下一月
//canvas.drawPath(surface.preMonthBtnPath, surface.monthChangeBtnPaint);
//canvas.drawPath(surface.nextMonthBtnPath, surface.monthChangeBtnPaint);
// 星期
float weekTextY = surface.monthHeight + surface.weekHeight * 3 / 4f;
// 星期背景
// surface.cellBgPaint.setColor(surface.textColor);
// canvas.drawRect(surface.weekHeight, surface.width, surface.weekHeight, surface.width, surface.cellBgPaint);
for (int i = 0; i < surface.weekText.length; i++) {
float weekTextX = i
* surface.cellWidth
+ (surface.cellWidth - surface.weekPaint
.measureText(surface.weekText[i])) / 2f;
canvas.drawText(surface.weekText[i], weekTextX, weekTextY,
surface.weekPaint);
} // 计算日期
calculateDate();
// 按下状态,选择状态背景色
drawDownOrSelectedBg(canvas);
// write date number
// today index
int todayIndex = -1;
calendar.setTime(curDate);
String curYearAndMonth = calendar.get(Calendar.YEAR) + ""
+ calendar.get(Calendar.MONTH);
calendar.setTime(today);
String todayYearAndMonth = calendar.get(Calendar.YEAR) + ""
+ calendar.get(Calendar.MONTH);
if (curYearAndMonth.equals(todayYearAndMonth)) {
int todayNumber = calendar.get(Calendar.DAY_OF_MONTH);
todayIndex = curStartIndex + todayNumber - 1;
}
for (int i = 0; i < 42; i++) {
int color = surface.textColor;
if (isLastMonth(i)) {
color = surface.borderColor;
} else if (isNextMonth(i)) {
color = surface.borderColor;
}
if (todayIndex != -1 && i == todayIndex) {
color = surface.todayNumberColor;
}
drawCellText(canvas, i, date[i] + "", color);
}
super.onDraw(canvas);
} private void calculateDate() {
calendar.setTime(curDate);
calendar.set(Calendar.DAY_OF_MONTH, 1);
int dayInWeek = calendar.get(Calendar.DAY_OF_WEEK);
Log.d(TAG, "day in week:" + dayInWeek);
int monthStart = dayInWeek;
if (monthStart == 1) {
monthStart = 8;
}
monthStart -= 1; //以日为开头-1,以星期一为开头-2
curStartIndex = monthStart;
date[monthStart] = 1;
// last month
if (monthStart > 0) {
calendar.set(Calendar.DAY_OF_MONTH, 0);
int dayInmonth = calendar.get(Calendar.DAY_OF_MONTH);
for (int i = monthStart - 1; i >= 0; i--) {
date[i] = dayInmonth;
dayInmonth--;
}
calendar.set(Calendar.DAY_OF_MONTH, date[0]);
}
showFirstDate = calendar.getTime();
// this month
calendar.setTime(curDate);
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 0);
// Log.d(TAG, "m:" + calendar.get(Calendar.MONTH) + " d:" +
// calendar.get(Calendar.DAY_OF_MONTH));
int monthDay = calendar.get(Calendar.DAY_OF_MONTH);
for (int i = 1; i < monthDay; i++) {
date[monthStart + i] = i + 1;
}
curEndIndex = monthStart + monthDay;
// next month
for (int i = monthStart + monthDay; i < 42; i++) {
date[i] = i - (monthStart + monthDay) + 1;
}
if (curEndIndex < 42) {
// 显示了下一月的
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
calendar.set(Calendar.DAY_OF_MONTH, date[41]);
showLastDate = calendar.getTime();
} /**
*
* @param canvas
* @param index
* @param text
*/
private void drawCellText(Canvas canvas, int index, String text, int color) {
int x = getXByIndex(index);
int y = getYByIndex(index);
surface.datePaint.setColor(color);
float cellY = surface.monthHeight + surface.weekHeight + (y - 1)
* surface.cellHeight + surface.cellHeight * 3 / 4f;
float cellX = (surface.cellWidth * (x - 1))
+ (surface.cellWidth - surface.datePaint.measureText(text))
/ 2f;
canvas.drawText(text, cellX, cellY, surface.datePaint);
} /**
*
* @param canvas
* @param index
* @param color
*/
private void drawCellBg(Canvas canvas, int index, int color) {
int x = getXByIndex(index);
int y = getYByIndex(index);
surface.cellBgPaint.setColor(color);
float left = surface.cellWidth * (x - 1) + surface.borderWidth;
float top = surface.monthHeight + surface.weekHeight + (y - 1)
* surface.cellHeight + surface.borderWidth;
canvas.drawRect(left, top, left + surface.cellWidth
- surface.borderWidth, top + surface.cellHeight
- surface.borderWidth, surface.cellBgPaint);
} private void drawDownOrSelectedBg(Canvas canvas) {
// down and not up
if (downDate != null) {
drawCellBg(canvas, downIndex, surface.cellDownColor);
}
// selected bg color
if (!selectedEndDate.before(showFirstDate)
&& !selectedStartDate.after(showLastDate)) {
int[] section = new int[] { -1, -1 };
calendar.setTime(curDate);
calendar.add(Calendar.MONTH, -1);
findSelectedIndex(0, curStartIndex, calendar, section);
if (section[1] == -1) {
calendar.setTime(curDate);
findSelectedIndex(curStartIndex, curEndIndex, calendar, section);
}
if (section[1] == -1) {
calendar.setTime(curDate);
calendar.add(Calendar.MONTH, 1);
findSelectedIndex(curEndIndex, 42, calendar, section);
}
if (section[0] == -1) {
section[0] = 0;
}
if (section[1] == -1) {
section[1] = 41;
}
for (int i = section[0]; i <= section[1]; i++) {
drawCellBg(canvas, i, surface.cellSelectedColor);
}
}
} private void findSelectedIndex(int startIndex, int endIndex,
Calendar calendar, int[] section) {
for (int i = startIndex; i < endIndex; i++) {
calendar.set(Calendar.DAY_OF_MONTH, date[i]);
Date temp = calendar.getTime();
// Log.d(TAG, "temp:" + temp.toLocaleString());
if (temp.compareTo(selectedStartDate) == 0) {
section[0] = i;
}
if (temp.compareTo(selectedEndDate) == 0) {
section[1] = i;
return;
}
}
} public Date getSelectedStartDate() {
return selectedStartDate;
} public Date getSelectedEndDate() {
return selectedEndDate;
} private boolean isLastMonth(int i) {
if (i < curStartIndex) {
return true;
}
return false;
} private boolean isNextMonth(int i) {
if (i >= curEndIndex) {
return true;
}
return false;
} private int getXByIndex(int i) {
return i % 7 + 1; // 1 2 3 4 5 6 7
} private int getYByIndex(int i) {
return i / 7 + 1; // 1 2 3 4 5 6
} // 获得当前应该显示的年月
public String getYearAndmonth() {
calendar.setTime(curDate);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
return year + "-" + surface.monthText[month];
} //上一月
public String clickLeftMonth(){
calendar.setTime(curDate);
calendar.add(Calendar.MONTH, -1);
curDate = calendar.getTime();
invalidate();
return getYearAndmonth();
}
//下一月
public String clickRightMonth(){
calendar.setTime(curDate);
calendar.add(Calendar.MONTH, 1);
curDate = calendar.getTime();
invalidate();
return getYearAndmonth();
} private void setSelectedDateByCoor(float x, float y) {
// change month
// if (y < surface.monthHeight) {
// // pre month
// if (x < surface.monthChangeWidth) {
// calendar.setTime(curDate);
// calendar.add(Calendar.MONTH, -1);
// curDate = calendar.getTime();
// }
// // next month
// else if (x > surface.width - surface.monthChangeWidth) {
// calendar.setTime(curDate);
// calendar.add(Calendar.MONTH, 1);
// curDate = calendar.getTime();
// }
// }
// cell click down
if (y > surface.monthHeight + surface.weekHeight) {
int m = (int) (Math.floor(x / surface.cellWidth) + 1);
int n = (int) (Math
.floor((y - (surface.monthHeight + surface.weekHeight))
/ Float.valueOf(surface.cellHeight)) + 1);
downIndex = (n - 1) * 7 + m - 1;
Log.d(TAG, "downIndex:" + downIndex);
calendar.setTime(curDate);
if (isLastMonth(downIndex)) {
calendar.add(Calendar.MONTH, -1);
} else if (isNextMonth(downIndex)) {
calendar.add(Calendar.MONTH, 1);
}
calendar.set(Calendar.DAY_OF_MONTH, date[downIndex]);
downDate = calendar.getTime();
}
invalidate();
} @Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setSelectedDateByCoor(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
if (downDate != null) {
// if (!completed) {
// if (downDate.before(selectedStartDate)) {
// selectedEndDate = selectedStartDate;
// selectedStartDate = downDate;
// } else {
// selectedEndDate = downDate;
// }
// completed = true;
// } else {
// selectedStartDate = selectedEndDate = downDate;
// completed = false;
// }
selectedStartDate = selectedEndDate = downDate;
//响应监听事件
onItemClickListener.OnItemClick(selectedStartDate);
// Log.d(TAG, "downdate:" + downDate.toLocaleString());
//Log.d(TAG, "start:" + selectedStartDate.toLocaleString());
//Log.d(TAG, "end:" + selectedEndDate.toLocaleString());
downDate = null;
invalidate();
}
break;
}
return true;
} //给控件设置监听事件
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
//监听接口
public interface OnItemClickListener {
void OnItemClick(Date date);
} /**
*
* 1. 布局尺寸 2. 文字颜色,大小 3. 当前日期的颜色,选择的日期颜色
*/
private class Surface {
public float density;
public int width; // 整个控件的宽度
public int height; // 整个控件的高度
public float monthHeight; // 显示月的高度
//public float monthChangeWidth; // 上一月、下一月按钮宽度
public float weekHeight; // 显示星期的高度
public float cellWidth; // 日期方框宽度
public float cellHeight; // 日期方框高度
public float borderWidth;
public int bgColor = Color.parseColor("#FFFFFF");
private int textColor = Color.BLACK;
//private int textColorUnimportant = Color.parseColor("#666666");
private int btnColor = Color.parseColor("#666666");
private int borderColor = Color.parseColor("#CCCCCC");
public int todayNumberColor = Color.RED;
public int cellDownColor = Color.parseColor("#CCFFFF");
public int cellSelectedColor = Color.parseColor("#99CCFF");
public Paint borderPaint;
public Paint monthPaint;
public Paint weekPaint;
public Paint datePaint;
public Paint monthChangeBtnPaint;
public Paint cellBgPaint;
public Path boxPath; // 边框路径
//public Path preMonthBtnPath; // 上一月按钮三角形
//public Path nextMonthBtnPath; // 下一月按钮三角形
public String[] weekText = { "Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
public String[] monthText = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; public void init() {
float temp = height / 7f;
monthHeight = 0;//(float) ((temp + temp * 0.3f) * 0.6);
//monthChangeWidth = monthHeight * 1.5f;
weekHeight = (float) ((temp + temp * 0.3f) * 0.7);
cellHeight = (height - monthHeight - weekHeight) / 6f;
cellWidth = width / 7f;
borderPaint = new Paint();
borderPaint.setColor(borderColor);
borderPaint.setStyle(Paint.Style.STROKE);
borderWidth = (float) (0.5 * density);
// Log.d(TAG, "borderwidth:" + borderWidth);
borderWidth = borderWidth < 1 ? 1 : borderWidth;
borderPaint.setStrokeWidth(borderWidth);
monthPaint = new Paint();
monthPaint.setColor(textColor);
monthPaint.setAntiAlias(true);
float textSize = cellHeight * 0.4f;
Log.d(TAG, "text size:" + textSize);
monthPaint.setTextSize(textSize);
monthPaint.setTypeface(Typeface.DEFAULT_BOLD);
weekPaint = new Paint();
weekPaint.setColor(textColor);
weekPaint.setAntiAlias(true);
float weekTextSize = weekHeight * 0.6f;
weekPaint.setTextSize(weekTextSize);
weekPaint.setTypeface(Typeface.DEFAULT_BOLD);
datePaint = new Paint();
datePaint.setColor(textColor);
datePaint.setAntiAlias(true);
float cellTextSize = cellHeight * 0.5f;
datePaint.setTextSize(cellTextSize);
datePaint.setTypeface(Typeface.DEFAULT_BOLD);
boxPath = new Path();
//boxPath.addRect(0, 0, width, height, Direction.CW);
//boxPath.moveTo(0, monthHeight);
boxPath.rLineTo(width, 0);
boxPath.moveTo(0, monthHeight + weekHeight);
boxPath.rLineTo(width, 0);
for (int i = 1; i < 6; i++) {
boxPath.moveTo(0, monthHeight + weekHeight + i * cellHeight);
boxPath.rLineTo(width, 0);
boxPath.moveTo(i * cellWidth, monthHeight);
boxPath.rLineTo(0, height - monthHeight);
}
boxPath.moveTo(6 * cellWidth, monthHeight);
boxPath.rLineTo(0, height - monthHeight);
//preMonthBtnPath = new Path();
//int btnHeight = (int) (monthHeight * 0.6f);
//preMonthBtnPath.moveTo(monthChangeWidth / 2f, monthHeight / 2f);
//preMonthBtnPath.rLineTo(btnHeight / 2f, -btnHeight / 2f);
//preMonthBtnPath.rLineTo(0, btnHeight);
//preMonthBtnPath.close();
//nextMonthBtnPath = new Path();
//nextMonthBtnPath.moveTo(width - monthChangeWidth / 2f,
// monthHeight / 2f);
//nextMonthBtnPath.rLineTo(-btnHeight / 2f, -btnHeight / 2f);
//nextMonthBtnPath.rLineTo(0, btnHeight);
//nextMonthBtnPath.close();
monthChangeBtnPaint = new Paint();
monthChangeBtnPaint.setAntiAlias(true);
monthChangeBtnPaint.setStyle(Paint.Style.FILL_AND_STROKE);
monthChangeBtnPaint.setColor(btnColor);
cellBgPaint = new Paint();
cellBgPaint.setAntiAlias(true);
cellBgPaint.setStyle(Paint.Style.FILL);
cellBgPaint.setColor(cellSelectedColor);
}
}
}

实现日历控件:

  1. <RelativeLayout
  2. android:id="@+id/layout_calendar"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content"
  5. android:visibility="visible" >
  6. <TextView
  7. android:id="@+id/calendarCenter"
  8. style="@style/main_bar_text_style"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:layout_centerHorizontal="true"
  12. android:layout_margin="8dp" />
  13. <ImageButton
  14. android:id="@+id/calendarLeft"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_alignParentLeft="true"
  18. android:padding="8dp"
  19. android:contentDescription="@null"
  20. android:src="@drawable/calendar_month_left"
  21. android:background="@null"/>
  22. <ImageButton
  23. android:id="@+id/calendarRight"
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:layout_alignParentRight="true"
  27. android:padding="8dp"
  28. android:contentDescription="@null"
  29. android:src="@drawable/calendar_month_right"
  30. android:background="@null"/>
  31. <com.techrare.view.CalendarView
  32. android:id="@+id/calendar"
  33. android:layout_width="fill_parent"
  34. android:layout_height="wrap_content"
  35. android:layout_alignParentLeft="true"
  36. android:layout_below="@+id/calendarCenter" />
  37. </RelativeLayout>
        <RelativeLayout
android:id="@+id/layout_calendar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="visible" > <TextView
android:id="@+id/calendarCenter"
style="@style/main_bar_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="8dp" /> <ImageButton
android:id="@+id/calendarLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:padding="8dp"
android:contentDescription="@null"
android:src="@drawable/calendar_month_left"
android:background="@null"/> <ImageButton
android:id="@+id/calendarRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="8dp"
android:contentDescription="@null"
android:src="@drawable/calendar_month_right"
android:background="@null"/> <com.techrare.view.CalendarView
android:id="@+id/calendar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/calendarCenter" />
</RelativeLayout>
  1. <style name="main_bar_text_style">
  2. <item name="android:textColor">@color/white</item>
  3. <item name="android:textStyle">bold</item>
  4. <item name="android:textSize">18sp</item>
  5. </style>
     <style name="main_bar_text_style">
<item name="android:textColor">@color/white</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">18sp</item>
</style>

上一月图片:

android 自定义日历控件

  1. 调用 calendar.clickLeftMonth();
调用 calendar.clickLeftMonth(); 

下一月:

android 自定义日历控件

  1. 调用 calendar.clickRightMonth();
调用 calendar.clickRightMonth(); 

日历控件中的一些功能(可以自己加):

  1. //获取日历控件对象
  2. calendar = (CalendarView)findViewById(R.id.calendar);
  3. //获取日历中年月 ya[0]为年,ya[1]为月(格式大家可以自行在日历控件中改)
  4. String[] ya = calendar.getYearAndmonth().split("-");
  5. //点击上一月 同样返回年月
  6. String leftYearAndmonth = calendar.clickLeftMonth();
  7. String[] lya = leftYearAndmonth.split("-");
  8. //点击下一月
  9. String rightYearAndmonth = calendar.clickRightMonth();
  10. String[] rya = rightYearAndmonth.split("-");
  11. //设置控件监听,可以监听到点击的每一天(大家也可以在控件中自行设定)
  12. calendar.setOnItemClickListener(new calendarItemClickListener());
  13. class calendarItemClickListener implements OnItemClickListener{
  14. @Override
  15. public void OnItemClick(Date date) {
  16. Toast.makeText(getApplicationContext(), date+"", Toast.LENGTH_SHORT).show();
  17. }
  18. }