时间:2021-05-19
前言
之前实现过《Android可签到的日历控件》的功能,跟这篇一样都是实现签到打卡功能,这篇实现的是按月进行打卡做标识,本篇内容实现的按周进行签到打卡。
实现签到规则如下:
1、连续签到7天,即可获得额外积分奖励。
2、连续签到记录在第8天开始时将清零重新计算。
3、如果中断签到,连续签到记录也将清零。
实现步骤:
1.效果图
2.自定义签到打卡View
3.主程序逻辑处理
4.主界面
5.签到bean
6.总结
实现过程:
1.效果图
2.自定义签到打卡View
/** * description: 自定义签到View. */public class StepsView extends View { /** * 动画执行的时间 230毫秒 */ private final static int ANIMATION_TIME = 230; /** * 动画执行的间隔次数 */ private final static int ANIMATION_INTERVAL = 10; /** * 线段的高度 */ private float mCompletedLineHeight = CalcUtils.dp2px(getContext(), 2f); /** * 图标宽度 */ private float mIconWidth = CalcUtils.dp2px(getContext(), 21.5f); /** * 图标的高度 */ private float mIconHeight = CalcUtils.dp2px(getContext(), 24f); /** * UP宽度 */ private float mUpWidth = CalcUtils.dp2px(getContext(), 20.5f); /** * up的高度 */ private float mUpHeight = CalcUtils.dp2px(getContext(), 12f); /** * 线段长度 */ private float mLineWidth = CalcUtils.dp2px(getContext(), 25f); /** * 已经完成的图标 */ private Drawable mCompleteIcon; /** * 正在进行的图标 */ private Drawable mAttentionIcon; /** * 默认的图标 */ private Drawable mDefaultIcon; /** * UP图标 */ private Drawable mUpIcon; /** * 图标中心点Y */ private float mCenterY; /** * 线段的左上方的Y */ private float mLeftY; /** * 线段的右下方的Y */ private float mRightY; /** * 数据源 */ private List<StepBean> mStepBeanList; private int mStepNum = 0; /** * 图标中心点位置 */ private List<Float> mCircleCenterPointPositionList; /** * 未完成的线段Paint */ private Paint mUnCompletedPaint; /** * 完成的线段paint */ private Paint mCompletedPaint; /** * 未完成颜色 */ private int mUnCompletedLineColor = ContextCompat.getColor(getContext(), R.color.c_d5a872); /** * 积分颜色 */ private int mUnCompletedTextColor = ContextCompat.getColor(getContext(), R.color.c_cccccc); /** * 天数颜色 */ private int mUnCompletedDayTextColor = ContextCompat.getColor(getContext(), R.color.c_736657); /** * up魅力值颜色 */ private int mCurrentTextColor = ContextCompat.getColor(getContext(), R.color.c_white); /** * 完成的颜色 */ private int mCompletedLineColor = ContextCompat.getColor(getContext(), R.color.c_d5a872); private Paint mTextNumberPaint; private Paint mTextDayPaint; /** * 是否执行动画 */ private boolean isAnimation = false; /** * 记录重绘次数 */ private int mCount = 0; /** * 执行动画线段每次绘制的长度,线段的总长度除以总共执行的时间乘以每次执行的间隔时间 */ private float mAnimationWidth = (mLineWidth / ANIMATION_TIME) * ANIMATION_INTERVAL; /** * 执行动画的位置 */ private int mPosition; private int[] mMax; public StepsView(Context context) { this(context, null); } public StepsView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public StepsView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } /** * init */ private void init() { mStepBeanList = new ArrayList<>(); mCircleCenterPointPositionList = new ArrayList<>(); //未完成文字画笔 mUnCompletedPaint = new Paint(); mUnCompletedPaint.setAntiAlias(true); mUnCompletedPaint.setColor(mUnCompletedLineColor); mUnCompletedPaint.setStrokeWidth(2); mUnCompletedPaint.setStyle(Paint.Style.FILL); //已完成画笔文字 mCompletedPaint = new Paint(); mCompletedPaint.setAntiAlias(true); mCompletedPaint.setColor(mCompletedLineColor); mCompletedPaint.setStrokeWidth(2); mCompletedPaint.setStyle(Paint.Style.FILL); //number paint mTextNumberPaint = new Paint(); mTextNumberPaint.setAntiAlias(true); mTextNumberPaint.setColor(mUnCompletedTextColor); mTextNumberPaint.setStyle(Paint.Style.FILL); mTextNumberPaint.setTextSize(CalcUtils.sp2px(getContext(), 10f)); //number paint mTextDayPaint = new Paint(); mTextDayPaint.setAntiAlias(true); mTextDayPaint.setColor(mUnCompletedDayTextColor); mTextDayPaint.setStyle(Paint.Style.FILL); mTextDayPaint.setTextSize(CalcUtils.sp2px(getContext(), 12f)); //已经完成的icon mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.sign); //正在进行的icon mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.unsign); //未完成的icon mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.unsign); //UP的icon mUpIcon = ContextCompat.getDrawable(getContext(), R.drawable.jifendikuai); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); setChange(); } private void setChange() { //图标的中中心Y点 mCenterY = CalcUtils.dp2px(getContext(), 28f) + mIconHeight / 2; //获取左上方Y的位置,获取该点的意义是为了方便画矩形左上的Y位置 mLeftY = mCenterY - (mCompletedLineHeight / 2); //获取右下方Y的位置,获取该点的意义是为了方便画矩形右下的Y位置 mRightY = mCenterY + mCompletedLineHeight / 2; //计算图标中心点 mCircleCenterPointPositionList.clear(); //第一个点距离父控件左边14.5dp float size = mIconWidth / 2 + CalcUtils.dp2px(getContext(), 23f); mCircleCenterPointPositionList.add(size); for (int i = 1; i < mStepNum; i++) { //从第二个点开始,每个点距离上一个点为图标的宽度加上线段的23dp的长度 size = size + mIconWidth + mLineWidth; mCircleCenterPointPositionList.add(size); } } @SuppressLint("DrawAllocation") @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); if (mStepBeanList.size() != 0) { if (isAnimation) { drawSign(canvas); } else { drawUnSign(canvas); } } } /** * 绘制签到(伴随签到动画) */ @SuppressLint("DrawAllocation") private void drawSign(Canvas canvas) { for (int i = 0; i < mCircleCenterPointPositionList.size(); i++) { //绘制线段 float preComplectedXPosition = mCircleCenterPointPositionList.get(i) + mIconWidth / 2; if (i != mCircleCenterPointPositionList.size() - 1) { //最后一条不需要绘制 if (mStepBeanList.get(i + 1).getState() == StepBean.STEP_COMPLETED) { //下一个是已完成,当前才需要绘制 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mCompletedPaint); } else { //其余绘制灰色 //当前位置执行动画 if (i == mPosition - 1) { //绿色开始绘制的地方, float endX = preComplectedXPosition + mAnimationWidth * (mCount / ANIMATION_INTERVAL); //绘制 canvas.drawRect(preComplectedXPosition, mLeftY, endX, mRightY, mCompletedPaint); //绘制 canvas.drawRect(endX, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } else { canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } } } //绘制图标 float currentComplectedXPosition = mCircleCenterPointPositionList.get(i); Rect rect = new Rect((int) (currentComplectedXPosition - mIconWidth / 2), (int) (mCenterY - mIconHeight / 2), (int) (currentComplectedXPosition + mIconWidth / 2), (int) (mCenterY + mIconHeight / 2)); StepBean stepsBean = mStepBeanList.get(i); if (i == mPosition && mCount == ANIMATION_TIME) { //当前需要绘制 mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } else { if (stepsBean.getState() == StepBean.STEP_UNDO) { mDefaultIcon.setBounds(rect); mDefaultIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_CURRENT) { mAttentionIcon.setBounds(rect); mAttentionIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_COMPLETED) { mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } } //绘制图标 if (stepsBean.getState() == StepBean.STEP_COMPLETED || (i == mPosition && mCount == ANIMATION_TIME)) { //已经完成了或者是当前动画完成并且需要当前位置需要改变 if (stepsBean.getNumber() != 0) { //是up的需要橙色 mTextNumberPaint.setColor(mCurrentTextColor); } else { //普通完成的颜色 mTextNumberPaint.setColor(mCompletedLineColor); } } else { //还没签到的,颜色均为灰色 mTextNumberPaint.setColor(mUnCompletedLineColor); } //绘制UP if (stepsBean.getNumber() != 0) { //需要UP才进行绘制 Rect rectUp = new Rect((int) (currentComplectedXPosition - mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 8f) - mUpHeight), (int) (currentComplectedXPosition + mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 1f))); mUpIcon.setBounds(rectUp); mUpIcon.draw(canvas); } //0表示不需要显示积分,非0表示需要消失积分 if (stepsBean.getNumber() != 0) { canvas.drawText("+" + stepsBean.getNumber(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 8f), mCenterY / 2 - CalcUtils.dp2px(getContext(), 0.5f), mTextNumberPaint); } //天数文字 canvas.drawText(stepsBean.getDay(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 12f), mCenterY + CalcUtils.dp2px(getContext(), 30f), mTextDayPaint); } //记录重绘次数 mCount = mCount + ANIMATION_INTERVAL; if (mCount <= ANIMATION_TIME) { //引起重绘 postInvalidate(); } else { //重绘完成 isAnimation = false; mCount = 0; } } /** * 绘制初始状态的view */ @SuppressLint("DrawAllocation") private void drawUnSign(Canvas canvas) { for (int i = 0; i < mCircleCenterPointPositionList.size(); i++) { //绘制线段 float preComplectedXPosition = mCircleCenterPointPositionList.get(i) + mIconWidth / 2; if (i != mCircleCenterPointPositionList.size() - 1) { //最后一条不需要绘制 if (mStepBeanList.get(i + 1).getState() == StepBean.STEP_COMPLETED) { //下一个是已完成,当前才需要绘制 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mCompletedPaint); } else { //其余绘制灰色 canvas.drawRect(preComplectedXPosition, mLeftY, preComplectedXPosition + mLineWidth, mRightY, mUnCompletedPaint); } } //绘制图标 float currentComplectedXPosition = mCircleCenterPointPositionList.get(i); Rect rect = new Rect((int) (currentComplectedXPosition - mIconWidth / 2), (int) (mCenterY - mIconHeight / 2), (int) (currentComplectedXPosition + mIconWidth / 2), (int) (mCenterY + mIconHeight / 2)); StepBean stepsBean = mStepBeanList.get(i); if (stepsBean.getState() == StepBean.STEP_UNDO) { mDefaultIcon.setBounds(rect); mDefaultIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_CURRENT) { mAttentionIcon.setBounds(rect); mAttentionIcon.draw(canvas); } else if (stepsBean.getState() == StepBean.STEP_COMPLETED) { mCompleteIcon.setBounds(rect); mCompleteIcon.draw(canvas); } //绘制增加的分数数目 if (stepsBean.getState() == StepBean.STEP_COMPLETED) { //已经完成了 if (stepsBean.getNumber() != 0) { //是up的需要橙色 mTextNumberPaint.setColor(mCurrentTextColor); } else { //普通完成的颜色 mTextNumberPaint.setColor(mCompletedLineColor); } } else { //还没签到的,颜色均为灰色 mTextNumberPaint.setColor(mUnCompletedLineColor); } //绘制UP if (stepsBean.getNumber() != 0) { //需要UP才进行绘制 Rect rectUp = new Rect((int) (currentComplectedXPosition - mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 8f) - mUpHeight), (int) (currentComplectedXPosition + mUpWidth / 2), (int) (mCenterY - mIconHeight / 2 - CalcUtils.dp2px(getContext(), 1f))); mUpIcon.setBounds(rectUp); mUpIcon.draw(canvas); } //0表示不需要显示积分,非0表示需要消失积分 if (stepsBean.getNumber() != 0) { //积分文字 canvas.drawText("+" + stepsBean.getNumber(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 8f), mCenterY / 2 - CalcUtils.dp2px(getContext(), 0.5f), mTextNumberPaint); } //天数文字 canvas.drawText(stepsBean.getDay(), currentComplectedXPosition - CalcUtils.dp2px(getContext(), 12f), mCenterY + CalcUtils.dp2px(getContext(), 30f), mTextDayPaint); } } /** * 设置流程步数 * * @param stepsBeanList 流程步数 */ public void setStepNum(List<StepBean> stepsBeanList) { if (stepsBeanList == null && stepsBeanList.size() == 0) { return; } mStepBeanList = stepsBeanList; mStepNum = mStepBeanList.size(); setChange();//重新绘制 //引起重绘 postInvalidate(); } /** * 执行签到动画 * * @param position 执行的位置 */ public void startSignAnimation(int position) { //线条从灰色变为绿色 isAnimation = true; mPosition = position; //引起重绘 postInvalidate(); }}3.主程序逻辑处理
4.主界面布局文件
5.签到bean
6.总结
该篇的功能是根据需求进行功能的处理,自定义View是实现了签到时的动画效果的,不过我们的需求不需要动画,所以这里就没调用演示,需要的可以自行调用
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
产品要做签到功能,签到功能要基于一个日历来进行,所以就根据要求自定义了一个日历自定义控件相信做android都知道:(1)首先创建一个类,继承一个容器类或者是一
本文实例为大家分享了Android自定义控件ViewGroup实现标签云的具体代码,供大家参考,具体内容如下实现的功能:基本绘制流程:构造函数获取自定义属性on
本文实例讲述了Android编程实现自定义toast。分享给大家供大家参考,具体如下:效果图:代码://自定义布局的toastcustomViewToast.s
本文实例为大家分享了Android自定义View图片按Path运动旋转的具体代码,供大家参考,具体内容如下View:/***author:stone*email
本文实例为大家分享了Android自定义View实现抖音飘动红心效果的具体代码,供大家参考,具体内容如下自定义View——抖音飘动红心效果展示动画效果使用自定义