Android自定义view实现日历打卡签到
更新时间:2021年5月9日 15:01 点击:2104
本文实例为大家分享了Android自定义view实现日历打卡签到的具体代码,供大家参考,具体内容如下
1.说明
自己写一个view实现每天签到的功能,设置背景图片
源码下载
2.效果图
3.主界面
package com.example.myapplication30; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.ArrayList; import java.util.Calendar; import java.util.List; public class MainActivity extends AppCompatActivity { //参考网址:https://blog.csdn.net/MacaoPark/article/details/102069775 private TextView mTvDaySum; private TextView mTvMonth; private SignView mCvCalendar; private List<SignEntity> data; private Calendar calendar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvDaySum = findViewById(R.id.punch_tv_day_sum); mTvMonth = findViewById(R.id.punch_tv_month); mCvCalendar = findViewById(R.id.punch_cv_calendar); } @Override protected void onStart() { super.onStart(); onReady(); } @SuppressLint("SetTextI18n") private void onReady() { calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); //int date = calendar.get(Calendar.DATE); int dayOfMonthToday = calendar.get(Calendar.DAY_OF_MONTH); List<SignDate> signDates = new ArrayList<>(); signDates.add(new SignDate(2021, 5, 1, true)); signDates.add(new SignDate(2021, 5, 2, true)); signDates.add(new SignDate(2021, 5, 3, true)); signDates.add(new SignDate(2021, 5, 4, true)); signDates.add(new SignDate(2021, 5, 5, true)); mTvDaySum.setText("本期连续登录\t"+signDates.size()+"\t天"); mTvMonth.setText(year+"年"+getResources().getStringArray(R.array.month_array)[month]+"\t"+dayOfMonthToday+"日"); data = new ArrayList<>(); for (int i = 1; i <= dayOfMonthToday; i++) { SignEntity signEntity = new SignEntity(); if (i == dayOfMonthToday) { signEntity.setDayType(2); } else { signEntity.setDayType(1); } for (int j = 0; j < signDates.size(); j++) { if (signDates.get(j).getDay() == i) { signEntity.setDayType(0); break; } else if (dayOfMonthToday == i) { signEntity.setDayType(2); } else { signEntity.setDayType(1); } } data.add(signEntity); } SignAdapter signAdapter = new SignAdapter(data); mCvCalendar.setAdapter(signAdapter); } }
4.适配器
package com.example.myapplication30; import java.util.List; /** * SignAdapter * Created by E.M on 2016/4/21. */ public class SignAdapter extends CalendarAdapter { private List<SignEntity> data; public SignAdapter(List<SignEntity> data) { this.data = data; } @Override public SignView.DayType getType(int dayOfMonth) { return SignView.DayType.valueOf(data.get(dayOfMonth - 1).getDayType()); } }
5.自定义view
package com.example.myapplication30; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ComposeShader; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.Calendar; /** * 签到日历控件 * Created by E.M on 2016/4/20. */ public class SignView extends View { private static final String[] WEEK_MARK = {"一", "二", "三", "四", "五", "六", "日"}; private static final int MAX_COLUMN = 7; /** * 周内 */ private static final int COLOR_MARKER_WEEKDAY = 0xFF999999; private static final int COLOR_MARKER_WEEKEND = 0xFF1B89CD; /** * 已签到背景色 */ //private static final int COLOR_BACKGROUND_HIGHLIGHT = 0xFFFF0000; /** * 未签到背景色 */ private static final int COLOR_BACKGROUND_NORMAL = 0xFF9C9C9C; /** * 等待签到背景色 */ private static final int COLOR_BACKGROUND_WAIT = 0xFFFE7471; /** * 已签到文字颜色 */ private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF; /** * 未签到文字颜色 */ private static final int COLOR_TEXT_NORMAL = 0xFF606060; // /** // * 不可用文字颜色 // */ // private static final int COLOR_TEXT_DISABLED = 0xFFD4D4D4; private static final int MARKER_TEXT_SIZE = 40; private static final int CELL_TEXT_SIZE = 40; private static final int VERTICAL_SPACE = 51; private static final int VERTICAL_MARGIN = 62; private static final int HORIZONTAL_MARGIN = 39; private static final int CELL_SIZE = 80; private static final int WAIT_LINE_SIZE = 14; private int dayOfMonthToday; private int markerTextY; private int verticalCellTop; private int sumDayOfMonth; private int daysOfFirstWeek; private int horizontalSpace; private int deltaTextCellY; private int deltaTextMarkerY; private int verticalSpace; private int verticalMargin; private int horizontalMargin; private int cellSize; private int waitLineSize; private Path waitPath; private Rect waitRect; private Paint paintWeekday; private Paint paintWeekend; private Paint paintTextNormal; private Paint paintTextHighlight; private Paint paintBackgroundWait; private Paint paintBackgroundNormal; private Paint paintBackgroundHighlight; private CalendarAdapter adapter; public SignView(Context context) { this(context, null); } public SignView(Context context, AttributeSet attrs) { this(context, attrs, -1); } public SignView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initResolution(); initPaint(); initData(); } private void initResolution() { // resolutionUtil = ResolutionUtil.getInstance(); // verticalSpace = resolutionUtil.formatVertical(VERTICAL_SPACE); // verticalMargin = resolutionUtil.formatVertical(VERTICAL_MARGIN); // horizontalMargin = resolutionUtil.formatHorizontal(HORIZONTAL_MARGIN); // cellSize = resolutionUtil.formatVertical(CELL_SIZE); // waitLineSize = resolutionUtil.formatVertical(WAIT_LINE_SIZE); verticalSpace = VERTICAL_SPACE; verticalMargin = VERTICAL_MARGIN; horizontalMargin = HORIZONTAL_MARGIN; cellSize = CELL_SIZE; waitLineSize = WAIT_LINE_SIZE; } private void initPaint() { // int markerTextSize = resolutionUtil.formatVertical(MARKER_TEXT_SIZE); // int cellTextSize = resolutionUtil.formatVertical(CELL_TEXT_SIZE); int markerTextSize = MARKER_TEXT_SIZE; int cellTextSize = CELL_TEXT_SIZE; paintWeekday = new Paint(); paintWeekday.setAntiAlias(true); paintWeekday.setColor(COLOR_MARKER_WEEKDAY); paintWeekday.setTextSize(markerTextSize); paintWeekday.setTextAlign(Paint.Align.CENTER); paintWeekend = new Paint(); paintWeekend.setAntiAlias(true); paintWeekend.setColor(COLOR_MARKER_WEEKEND); paintWeekend.setTextSize(markerTextSize); paintWeekend.setTextAlign(Paint.Align.CENTER); paintTextNormal = new Paint(); paintTextNormal.setAntiAlias(true); paintTextNormal.setColor(COLOR_TEXT_NORMAL); paintTextNormal.setTextSize(cellTextSize); paintTextNormal.setTextAlign(Paint.Align.CENTER); paintTextHighlight = new Paint(); paintTextHighlight.setAntiAlias(true); paintTextHighlight.setColor(COLOR_TEXT_HIGHLIGHT); paintTextHighlight.setTextSize(cellTextSize); paintTextHighlight.setTextAlign(Paint.Align.CENTER); paintBackgroundWait = new Paint(); paintBackgroundWait.setAntiAlias(true); paintBackgroundWait.setColor(COLOR_BACKGROUND_WAIT); paintBackgroundWait.setStrokeWidth(2); paintBackgroundWait.setStyle(Paint.Style.STROKE); paintBackgroundNormal = new Paint(); paintBackgroundNormal.setAntiAlias(true); paintBackgroundNormal.setColor(COLOR_BACKGROUND_NORMAL); paintBackgroundNormal.setStrokeWidth(2); paintBackgroundNormal.setStyle(Paint.Style.STROKE); paintBackgroundHighlight = new Paint(); paintBackgroundHighlight.setAntiAlias(true); paintBackgroundHighlight.setStrokeWidth(2); paintBackgroundHighlight.setStyle(Paint.Style.FILL); //颜色 //paintBackgroundHighlight.setColor(COLOR_BACKGROUND_HIGHLIGHT); //多种颜色数组 //int[] colors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA}; //float[] position = {0f, 0.2f, 0.4f, 0.6f, 1.0f}; //Shader shader1 = new LinearGradient(100,850,600,850,colors,position,Shader.TileMode.CLAMP); //paintBackgroundHighlight.setShader(shader1); //设置背景图片 /* Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.small); Shader shader1 = new BitmapShader(placeholder, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); paintBackgroundHighlight.setShader(shader1);*/ } private void initData() { Paint.FontMetricsInt fmiMarker = paintWeekday.getFontMetricsInt(); deltaTextMarkerY = -(fmiMarker.bottom - fmiMarker.top) / 2 - fmiMarker.top; markerTextY = verticalMargin + cellSize / 2; Paint.FontMetricsInt fmiCell = paintTextNormal.getFontMetricsInt(); deltaTextCellY = -(fmiCell.bottom - fmiCell.top) / 2 - fmiCell.top; verticalCellTop = verticalMargin + cellSize; Calendar calendarToday = Calendar.getInstance(); dayOfMonthToday = calendarToday.get(Calendar.DAY_OF_MONTH); int dayOfWeek; sumDayOfMonth = calendarToday.getActualMaximum(Calendar.DAY_OF_MONTH); Calendar calendarFirstDay = Calendar.getInstance(); calendarFirstDay.set(Calendar.DAY_OF_MONTH, 1); dayOfWeek = calendarFirstDay.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == Calendar.SUNDAY) { dayOfWeek = 7; } else { dayOfWeek = dayOfWeek - 1; } daysOfFirstWeek = MAX_COLUMN - dayOfWeek + 1; } private void createWaitBackground(int topX, int topY) { waitPath = new Path(); waitPath.moveTo(topX, topY + waitLineSize); waitPath.lineTo(topX, topY); waitPath.lineTo(topX + waitLineSize, topY); waitPath.moveTo(topX + cellSize - waitLineSize, topY + cellSize); waitPath.lineTo(topX + cellSize, topY + cellSize); waitPath.lineTo(topX + cellSize, topY + cellSize - waitLineSize); waitRect = new Rect(topX, topY, topX + cellSize, topY + cellSize); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); horizontalSpace = (w - MAX_COLUMN * cellSize - horizontalMargin * 2) / (MAX_COLUMN - 1); } @Override public void draw(Canvas canvas) { super.draw(canvas); drawWeekMark(canvas); drawCellsBackground(canvas); drawCells(canvas); } private void drawWeekMark(Canvas canvas) { int y = markerTextY + deltaTextMarkerY; for (int i = 0; i < 7; i++) { int x = horizontalMargin + i * (horizontalSpace + cellSize) + cellSize / 2; if (i < 5) { canvas.drawText(WEEK_MARK[i], x, y, paintWeekday); } else { canvas.drawText(WEEK_MARK[i], x, y, paintWeekend); } } } private void drawCellsBackground(Canvas canvas) { for (int i = 1; i <= dayOfMonthToday; i++) { drawCellBackground(canvas, i, getColumnIndex(i), getRowIndex(i)); } } /** * 根据行列序号绘制日期背景 * * @param canvas 画布 * @param dayOfMonth 日期 * @param column 列序号 * @param row 行序号 */ private void drawCellBackground(Canvas canvas, int dayOfMonth, int column, int row) { int x = horizontalMargin + column * (horizontalSpace + cellSize) + cellSize / 2; int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2; if (adapter != null) { DayType dayType = adapter.getType(dayOfMonth); switch (dayType) { case WAITING: if (waitPath == null) { createWaitBackground(x - cellSize / 2, y - cellSize / 2); } canvas.drawPath(waitPath, paintBackgroundWait); break; case SIGNED: // canvas.drawCircle(x, y, cellSize/2, paintBackgroundHighlight); // canvas.drawRect(x - 60, y - 60, x + 60, y + 60, paintBackgroundHighlight);// 正方形 // Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.purtest); // canvas.drawBitmap(placeholder,);wCircle(x, y, cellSize/2, paintBackgroundHighlight); canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.small3),x-40, y-40 , paintBackgroundHighlight); break; default: canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal); break; } } else { canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal); } } private void drawCells(Canvas canvas) { for (int i = 1; i <= sumDayOfMonth; i++) { drawCell(canvas, i, getColumnIndex(i), getRowIndex(i)); } } /** * 根据行列序号绘制日期 * * @param canvas 画布 * @param dayOfMonth 日期 * @param column 列序号 * @param row 行序号 */ private void drawCell(Canvas canvas, int dayOfMonth, int column, int row) { int x = horizontalMargin + column * (horizontalSpace + cellSize) + cellSize / 2; int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2 + deltaTextCellY; if (adapter != null && dayOfMonth <= dayOfMonthToday) { DayType dayType = adapter.getType(dayOfMonth); Paint paint; switch (dayType) { case SIGNED: paint = paintTextHighlight; break; default: paint = paintTextNormal; break; } canvas.drawText(String.valueOf(dayOfMonth), x, y, paint); } else { canvas.drawText(String.valueOf(dayOfMonth), x, y, paintTextNormal); } } /** * 获取列序号 * * @param dayOfMonth 日期 * @return 列序号 */ private int getColumnIndex(int dayOfMonth) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == Calendar.SUNDAY) { dayOfWeek = 6; } else { dayOfWeek = dayOfWeek - 2; } return dayOfWeek; } /** * 获取行序号 * * @param dayOfMonth 日期 * @return 行序号 */ private int getRowIndex(int dayOfMonth) { float weight = (dayOfMonth - daysOfFirstWeek) / (MAX_COLUMN * 1f); double rowIndexDouble = Math.abs(Math.ceil(weight)); return (int) rowIndexDouble; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { float x = event.getX(); float y = event.getY(); if (waitPath != null) { if (adapter.getType(dayOfMonthToday).equals(DayType.WAITING)) { if (x >= waitRect.left && y >= waitRect.top && x <= waitRect.right && y <= waitRect.bottom) { if (onTodayClickListener != null) { onTodayClickListener.onTodayClick(); } } } } } return true; } public void setAdapter(CalendarAdapter adapter) { this.adapter = adapter; this.invalidate(); } public int getDayOfMonthToday() { return dayOfMonthToday; } public void notifyDataSetChanged() { invalidate(); } private OnTodayClickListener onTodayClickListener; public void setOnTodayClickListener(OnTodayClickListener onTodayClickListener) { this.onTodayClickListener = onTodayClickListener; } public interface OnTodayClickListener { void onTodayClick(); } public enum DayType { /** * 已签到状态,时间已过 */ SIGNED(0), /** * 未签到状态,时间已过 */ UNSIGNED(1), /** * 等待状态,即当日还未签到 */ WAITING(2), /** * 不可达到状态,未到时间 */ UNREACHABLE(3), /** * 不可用状态,非当前月份 */ DISABLED(4); private int value; DayType(int value) { this.value = value; } public int getValue() { return value; } public static DayType valueOf(int value) { switch (value) { case 0: return SIGNED; case 1: return UNSIGNED; case 2: return WAITING; case 3: return UNREACHABLE; case 4: return DISABLED; default: return DISABLED; } } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
相关文章
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
- java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
- TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
android.os.BinderProxy cannot be cast to com解决办法
本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20- 这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
- 下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
- 首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
- 下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
用Intel HAXM给Android模拟器Emulator加速
Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20- 在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
Android开发中布局中的onClick简单完成多控件时的监听的利与弊
本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤
Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20- 这篇文章主要为大家详细介绍了Android实现简单用户注册案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-26