经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android自定义view实现日历打卡签到
来源:jb51  时间:2021/5/10 8:46:00  对本文有异议

本文实例为大家分享了Android自定义view实现日历打卡签到的具体代码,供大家参考,具体内容如下

1.说明

自己写一个view实现每天签到的功能,设置背景图片

源码下载

2.效果图

3.主界面

  1. package com.example.myapplication30;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.widget.Button;
  8. import android.widget.TextView;
  9. import java.util.ArrayList;
  10. import java.util.Calendar;
  11. import java.util.List;
  12. public class MainActivity extends AppCompatActivity {
  13. //参考网址:https://blog.csdn.net/MacaoPark/article/details/102069775
  14. private TextView mTvDaySum;
  15. private TextView mTvMonth;
  16. private SignView mCvCalendar;
  17. private List<SignEntity> data;
  18. private Calendar calendar;
  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.activity_main);
  23. mTvDaySum = findViewById(R.id.punch_tv_day_sum);
  24. mTvMonth = findViewById(R.id.punch_tv_month);
  25. mCvCalendar = findViewById(R.id.punch_cv_calendar);
  26. }
  27. @Override
  28. protected void onStart() {
  29. super.onStart();
  30. onReady();
  31. }
  32. @SuppressLint("SetTextI18n")
  33. private void onReady() {
  34. calendar = Calendar.getInstance();
  35. int year = calendar.get(Calendar.YEAR);
  36. int month = calendar.get(Calendar.MONTH);
  37. //int date = calendar.get(Calendar.DATE);
  38. int dayOfMonthToday = calendar.get(Calendar.DAY_OF_MONTH);
  39. List<SignDate> signDates = new ArrayList<>();
  40. signDates.add(new SignDate(2021, 5, 1, true));
  41. signDates.add(new SignDate(2021, 5, 2, true));
  42. signDates.add(new SignDate(2021, 5, 3, true));
  43. signDates.add(new SignDate(2021, 5, 4, true));
  44. signDates.add(new SignDate(2021, 5, 5, true));
  45. mTvDaySum.setText("本期连续登录\t"+signDates.size()+"\t天");
  46. mTvMonth.setText(year+"年"+getResources().getStringArray(R.array.month_array)[month]+"\t"+dayOfMonthToday+"日");
  47. data = new ArrayList<>();
  48. for (int i = 1; i <= dayOfMonthToday; i++) {
  49. SignEntity signEntity = new SignEntity();
  50. if (i == dayOfMonthToday) {
  51. signEntity.setDayType(2);
  52. } else {
  53. signEntity.setDayType(1);
  54. }
  55. for (int j = 0; j < signDates.size(); j++) {
  56. if (signDates.get(j).getDay() == i) {
  57. signEntity.setDayType(0);
  58. break;
  59. } else if (dayOfMonthToday == i) {
  60. signEntity.setDayType(2);
  61. } else {
  62. signEntity.setDayType(1);
  63. }
  64. }
  65. data.add(signEntity);
  66. }
  67. SignAdapter signAdapter = new SignAdapter(data);
  68. mCvCalendar.setAdapter(signAdapter);
  69. }
  70. }

4.适配器

  1. package com.example.myapplication30;
  2. import java.util.List;
  3. /**
  4. * SignAdapter
  5. * Created by E.M on 2016/4/21.
  6. */
  7. public class SignAdapter extends CalendarAdapter {
  8. private List<SignEntity> data;
  9. public SignAdapter(List<SignEntity> data) {
  10. this.data = data;
  11. }
  12. @Override
  13. public SignView.DayType getType(int dayOfMonth) {
  14. return SignView.DayType.valueOf(data.get(dayOfMonth - 1).getDayType());
  15. }
  16. }

5.自定义view

  1. package com.example.myapplication30;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.BitmapShader;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.ComposeShader;
  9. import android.graphics.LinearGradient;
  10. import android.graphics.Paint;
  11. import android.graphics.Path;
  12. import android.graphics.PorterDuff;
  13. import android.graphics.RadialGradient;
  14. import android.graphics.Rect;
  15. import android.graphics.Shader;
  16. import android.graphics.SweepGradient;
  17. import android.util.AttributeSet;
  18. import android.view.MotionEvent;
  19. import android.view.View;
  20. import java.util.Calendar;
  21. /**
  22. * 签到日历控件
  23. * Created by E.M on 2016/4/20.
  24. */
  25. public class SignView extends View {
  26. private static final String[] WEEK_MARK = {"一", "二", "三", "四", "五", "六", "日"};
  27. private static final int MAX_COLUMN = 7;
  28. /**
  29. * 周内
  30. */
  31. private static final int COLOR_MARKER_WEEKDAY = 0xFF999999;
  32. private static final int COLOR_MARKER_WEEKEND = 0xFF1B89CD;
  33. /**
  34. * 已签到背景色
  35. */
  36. //private static final int COLOR_BACKGROUND_HIGHLIGHT = 0xFFFF0000;
  37. /**
  38. * 未签到背景色
  39. */
  40. private static final int COLOR_BACKGROUND_NORMAL = 0xFF9C9C9C;
  41. /**
  42. * 等待签到背景色
  43. */
  44. private static final int COLOR_BACKGROUND_WAIT = 0xFFFE7471;
  45. /**
  46. * 已签到文字颜色
  47. */
  48. private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF;
  49. /**
  50. * 未签到文字颜色
  51. */
  52. private static final int COLOR_TEXT_NORMAL = 0xFF606060;
  53. // /**
  54. // * 不可用文字颜色
  55. // */
  56. // private static final int COLOR_TEXT_DISABLED = 0xFFD4D4D4;
  57. private static final int MARKER_TEXT_SIZE = 40;
  58. private static final int CELL_TEXT_SIZE = 40;
  59. private static final int VERTICAL_SPACE = 51;
  60. private static final int VERTICAL_MARGIN = 62;
  61. private static final int HORIZONTAL_MARGIN = 39;
  62. private static final int CELL_SIZE = 80;
  63. private static final int WAIT_LINE_SIZE = 14;
  64. private int dayOfMonthToday;
  65. private int markerTextY;
  66. private int verticalCellTop;
  67. private int sumDayOfMonth;
  68. private int daysOfFirstWeek;
  69. private int horizontalSpace;
  70. private int deltaTextCellY;
  71. private int deltaTextMarkerY;
  72. private int verticalSpace;
  73. private int verticalMargin;
  74. private int horizontalMargin;
  75. private int cellSize;
  76. private int waitLineSize;
  77. private Path waitPath;
  78. private Rect waitRect;
  79. private Paint paintWeekday;
  80. private Paint paintWeekend;
  81. private Paint paintTextNormal;
  82. private Paint paintTextHighlight;
  83. private Paint paintBackgroundWait;
  84. private Paint paintBackgroundNormal;
  85. private Paint paintBackgroundHighlight;
  86. private CalendarAdapter adapter;
  87. public SignView(Context context) {
  88. this(context, null);
  89. }
  90. public SignView(Context context, AttributeSet attrs) {
  91. this(context, attrs, -1);
  92. }
  93. public SignView(Context context, AttributeSet attrs, int defStyleAttr) {
  94. super(context, attrs, defStyleAttr);
  95. initResolution();
  96. initPaint();
  97. initData();
  98. }
  99. private void initResolution() {
  100. // resolutionUtil = ResolutionUtil.getInstance();
  101. // verticalSpace = resolutionUtil.formatVertical(VERTICAL_SPACE);
  102. // verticalMargin = resolutionUtil.formatVertical(VERTICAL_MARGIN);
  103. // horizontalMargin = resolutionUtil.formatHorizontal(HORIZONTAL_MARGIN);
  104. // cellSize = resolutionUtil.formatVertical(CELL_SIZE);
  105. // waitLineSize = resolutionUtil.formatVertical(WAIT_LINE_SIZE);
  106. verticalSpace = VERTICAL_SPACE;
  107. verticalMargin = VERTICAL_MARGIN;
  108. horizontalMargin = HORIZONTAL_MARGIN;
  109. cellSize = CELL_SIZE;
  110. waitLineSize = WAIT_LINE_SIZE;
  111. }
  112. private void initPaint() {
  113. // int markerTextSize = resolutionUtil.formatVertical(MARKER_TEXT_SIZE);
  114. // int cellTextSize = resolutionUtil.formatVertical(CELL_TEXT_SIZE);
  115. int markerTextSize = MARKER_TEXT_SIZE;
  116. int cellTextSize = CELL_TEXT_SIZE;
  117. paintWeekday = new Paint();
  118. paintWeekday.setAntiAlias(true);
  119. paintWeekday.setColor(COLOR_MARKER_WEEKDAY);
  120. paintWeekday.setTextSize(markerTextSize);
  121. paintWeekday.setTextAlign(Paint.Align.CENTER);
  122. paintWeekend = new Paint();
  123. paintWeekend.setAntiAlias(true);
  124. paintWeekend.setColor(COLOR_MARKER_WEEKEND);
  125. paintWeekend.setTextSize(markerTextSize);
  126. paintWeekend.setTextAlign(Paint.Align.CENTER);
  127. paintTextNormal = new Paint();
  128. paintTextNormal.setAntiAlias(true);
  129. paintTextNormal.setColor(COLOR_TEXT_NORMAL);
  130. paintTextNormal.setTextSize(cellTextSize);
  131. paintTextNormal.setTextAlign(Paint.Align.CENTER);
  132. paintTextHighlight = new Paint();
  133. paintTextHighlight.setAntiAlias(true);
  134. paintTextHighlight.setColor(COLOR_TEXT_HIGHLIGHT);
  135. paintTextHighlight.setTextSize(cellTextSize);
  136. paintTextHighlight.setTextAlign(Paint.Align.CENTER);
  137. paintBackgroundWait = new Paint();
  138. paintBackgroundWait.setAntiAlias(true);
  139. paintBackgroundWait.setColor(COLOR_BACKGROUND_WAIT);
  140. paintBackgroundWait.setStrokeWidth(2);
  141. paintBackgroundWait.setStyle(Paint.Style.STROKE);
  142. paintBackgroundNormal = new Paint();
  143. paintBackgroundNormal.setAntiAlias(true);
  144. paintBackgroundNormal.setColor(COLOR_BACKGROUND_NORMAL);
  145. paintBackgroundNormal.setStrokeWidth(2);
  146. paintBackgroundNormal.setStyle(Paint.Style.STROKE);
  147. paintBackgroundHighlight = new Paint();
  148. paintBackgroundHighlight.setAntiAlias(true);
  149. paintBackgroundHighlight.setStrokeWidth(2);
  150. paintBackgroundHighlight.setStyle(Paint.Style.FILL);
  151. //颜色
  152. //paintBackgroundHighlight.setColor(COLOR_BACKGROUND_HIGHLIGHT);
  153. //多种颜色数组
  154. //int[] colors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA};
  155. //float[] position = {0f, 0.2f, 0.4f, 0.6f, 1.0f};
  156. //Shader shader1 = new LinearGradient(100,850,600,850,colors,position,Shader.TileMode.CLAMP);
  157. //paintBackgroundHighlight.setShader(shader1);
  158. //设置背景图片
  159. /* Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.small);
  160. Shader shader1 = new BitmapShader(placeholder, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  161. paintBackgroundHighlight.setShader(shader1);*/
  162. }
  163. private void initData() {
  164. Paint.FontMetricsInt fmiMarker = paintWeekday.getFontMetricsInt();
  165. deltaTextMarkerY = -(fmiMarker.bottom - fmiMarker.top) / 2 - fmiMarker.top;
  166. markerTextY = verticalMargin + cellSize / 2;
  167. Paint.FontMetricsInt fmiCell = paintTextNormal.getFontMetricsInt();
  168. deltaTextCellY = -(fmiCell.bottom - fmiCell.top) / 2 - fmiCell.top;
  169. verticalCellTop = verticalMargin + cellSize;
  170. Calendar calendarToday = Calendar.getInstance();
  171. dayOfMonthToday = calendarToday.get(Calendar.DAY_OF_MONTH);
  172. int dayOfWeek;
  173. sumDayOfMonth = calendarToday.getActualMaximum(Calendar.DAY_OF_MONTH);
  174. Calendar calendarFirstDay = Calendar.getInstance();
  175. calendarFirstDay.set(Calendar.DAY_OF_MONTH, 1);
  176. dayOfWeek = calendarFirstDay.get(Calendar.DAY_OF_WEEK);
  177. if (dayOfWeek == Calendar.SUNDAY) {
  178. dayOfWeek = 7;
  179. } else {
  180. dayOfWeek = dayOfWeek - 1;
  181. }
  182. daysOfFirstWeek = MAX_COLUMN - dayOfWeek + 1;
  183. }
  184. private void createWaitBackground(int topX, int topY) {
  185. waitPath = new Path();
  186. waitPath.moveTo(topX, topY + waitLineSize);
  187. waitPath.lineTo(topX, topY);
  188. waitPath.lineTo(topX + waitLineSize, topY);
  189. waitPath.moveTo(topX + cellSize - waitLineSize, topY + cellSize);
  190. waitPath.lineTo(topX + cellSize, topY + cellSize);
  191. waitPath.lineTo(topX + cellSize, topY + cellSize - waitLineSize);
  192. waitRect = new Rect(topX, topY, topX + cellSize, topY + cellSize);
  193. }
  194. @Override
  195. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  196. super.onSizeChanged(w, h, oldw, oldh);
  197. horizontalSpace = (w - MAX_COLUMN * cellSize - horizontalMargin * 2) / (MAX_COLUMN - 1);
  198. }
  199. @Override
  200. public void draw(Canvas canvas) {
  201. super.draw(canvas);
  202. drawWeekMark(canvas);
  203. drawCellsBackground(canvas);
  204. drawCells(canvas);
  205. }
  206. private void drawWeekMark(Canvas canvas) {
  207. int y = markerTextY + deltaTextMarkerY;
  208. for (int i = 0; i < 7; i++) {
  209. int x = horizontalMargin + i * (horizontalSpace + cellSize)
  210. + cellSize / 2;
  211. if (i < 5) {
  212. canvas.drawText(WEEK_MARK[i], x, y, paintWeekday);
  213. } else {
  214. canvas.drawText(WEEK_MARK[i], x, y, paintWeekend);
  215. }
  216. }
  217. }
  218. private void drawCellsBackground(Canvas canvas) {
  219. for (int i = 1; i <= dayOfMonthToday; i++) {
  220. drawCellBackground(canvas, i, getColumnIndex(i), getRowIndex(i));
  221. }
  222. }
  223. /**
  224. * 根据行列序号绘制日期背景
  225. *
  226. * @param canvas 画布
  227. * @param dayOfMonth 日期
  228. * @param column 列序号
  229. * @param row 行序号
  230. */
  231. private void drawCellBackground(Canvas canvas, int dayOfMonth, int column, int row) {
  232. int x = horizontalMargin + column * (horizontalSpace + cellSize)
  233. + cellSize / 2;
  234. int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2;
  235. if (adapter != null) {
  236. DayType dayType = adapter.getType(dayOfMonth);
  237. switch (dayType) {
  238. case WAITING:
  239. if (waitPath == null) {
  240. createWaitBackground(x - cellSize / 2, y - cellSize / 2);
  241. }
  242. canvas.drawPath(waitPath, paintBackgroundWait);
  243. break;
  244. case SIGNED:
  245. // canvas.drawCircle(x, y, cellSize/2, paintBackgroundHighlight);
  246. // canvas.drawRect(x - 60, y - 60, x + 60, y + 60, paintBackgroundHighlight);// 正方形
  247. // Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.purtest);
  248. // canvas.drawBitmap(placeholder,);wCircle(x, y, cellSize/2, paintBackgroundHighlight);
  249. canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.small3),x-40, y-40 , paintBackgroundHighlight);
  250. break;
  251. default:
  252. canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);
  253. break;
  254. }
  255. } else {
  256. canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);
  257. }
  258. }
  259. private void drawCells(Canvas canvas) {
  260. for (int i = 1; i <= sumDayOfMonth; i++) {
  261. drawCell(canvas, i, getColumnIndex(i), getRowIndex(i));
  262. }
  263. }
  264. /**
  265. * 根据行列序号绘制日期
  266. *
  267. * @param canvas 画布
  268. * @param dayOfMonth 日期
  269. * @param column 列序号
  270. * @param row 行序号
  271. */
  272. private void drawCell(Canvas canvas, int dayOfMonth, int column, int row) {
  273. int x = horizontalMargin + column * (horizontalSpace + cellSize)
  274. + cellSize / 2;
  275. int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2
  276. + deltaTextCellY;
  277. if (adapter != null && dayOfMonth <= dayOfMonthToday) {
  278. DayType dayType = adapter.getType(dayOfMonth);
  279. Paint paint;
  280. switch (dayType) {
  281. case SIGNED:
  282. paint = paintTextHighlight;
  283. break;
  284. default:
  285. paint = paintTextNormal;
  286. break;
  287. }
  288. canvas.drawText(String.valueOf(dayOfMonth), x, y, paint);
  289. } else {
  290. canvas.drawText(String.valueOf(dayOfMonth), x, y, paintTextNormal);
  291. }
  292. }
  293. /**
  294. * 获取列序号
  295. *
  296. * @param dayOfMonth 日期
  297. * @return 列序号
  298. */
  299. private int getColumnIndex(int dayOfMonth) {
  300. Calendar calendar = Calendar.getInstance();
  301. calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
  302. int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
  303. if (dayOfWeek == Calendar.SUNDAY) {
  304. dayOfWeek = 6;
  305. } else {
  306. dayOfWeek = dayOfWeek - 2;
  307. }
  308. return dayOfWeek;
  309. }
  310. /**
  311. * 获取行序号
  312. *
  313. * @param dayOfMonth 日期
  314. * @return 行序号
  315. */
  316. private int getRowIndex(int dayOfMonth) {
  317. float weight = (dayOfMonth - daysOfFirstWeek) / (MAX_COLUMN * 1f);
  318. double rowIndexDouble = Math.abs(Math.ceil(weight));
  319. return (int) rowIndexDouble;
  320. }
  321. @Override
  322. public boolean onTouchEvent(MotionEvent event) {
  323. if (event.getAction() == MotionEvent.ACTION_UP) {
  324. float x = event.getX();
  325. float y = event.getY();
  326. if (waitPath != null) {
  327. if (adapter.getType(dayOfMonthToday).equals(DayType.WAITING)) {
  328. if (x >= waitRect.left && y >= waitRect.top && x <= waitRect.right && y <= waitRect.bottom) {
  329. if (onTodayClickListener != null) {
  330. onTodayClickListener.onTodayClick();
  331. }
  332. }
  333. }
  334. }
  335. }
  336. return true;
  337. }
  338. public void setAdapter(CalendarAdapter adapter) {
  339. this.adapter = adapter;
  340. this.invalidate();
  341. }
  342. public int getDayOfMonthToday() {
  343. return dayOfMonthToday;
  344. }
  345. public void notifyDataSetChanged() {
  346. invalidate();
  347. }
  348. private OnTodayClickListener onTodayClickListener;
  349. public void setOnTodayClickListener(OnTodayClickListener onTodayClickListener) {
  350. this.onTodayClickListener = onTodayClickListener;
  351. }
  352. public interface OnTodayClickListener {
  353. void onTodayClick();
  354. }
  355. public enum DayType {
  356. /**
  357. * 已签到状态,时间已过
  358. */
  359. SIGNED(0),
  360. /**
  361. * 未签到状态,时间已过
  362. */
  363. UNSIGNED(1),
  364. /**
  365. * 等待状态,即当日还未签到
  366. */
  367. WAITING(2),
  368. /**
  369. * 不可达到状态,未到时间
  370. */
  371. UNREACHABLE(3),
  372. /**
  373. * 不可用状态,非当前月份
  374. */
  375. DISABLED(4);
  376. private int value;
  377. DayType(int value) {
  378. this.value = value;
  379. }
  380. public int getValue() {
  381. return value;
  382. }
  383. public static DayType valueOf(int value) {
  384. switch (value) {
  385. case 0:
  386. return SIGNED;
  387. case 1:
  388. return UNSIGNED;
  389. case 2:
  390. return WAITING;
  391. case 3:
  392. return UNREACHABLE;
  393. case 4:
  394. return DISABLED;
  395. default:
  396. return DISABLED;
  397. }
  398. }
  399. }
  400. }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号