热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android自定义按周签到打卡功能实例代码

这篇文章主要给大家介绍了关于Android自定义实现按周签到打卡功能的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

之前实现过《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 mStepBeanList;
 private int mStepNum = 0;

 /**
 * 图标中心点位置
 */
 private List 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  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.主程序逻辑处理

/**
 * 一周签到规则:
 * 1、连续签到7天,即可额外获得15积分奖励
 * 2、连续签到记录在第8天开始时将清零重新计算
 * 3、如果中断签到,连续签到记录也将清零
 *
 * 注:可以显示签到的动画,这里没有使用动画
 * 需要动画可以调用mStepView.startSignAnimation(int position)
 * position表示需要做动画的位置
 */
public class MainActivity extends AppCompatActivity {

 private StepsView mStepView;
 private RelativeLayout rl_oval;
 private TextView text_sign;
 private TextView text_lianxusign;
 private ArrayList mStepBeans = new ArrayList<>();

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  initView();

  initData();

  initListener();
 }

 private void initListener() {

  rl_oval.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    //点击签到按钮,请求后台接口数据
    //模拟请求接口数据成功
    requestSuccessData();
   }
  });
 }

 /**
  * 模拟请求接口数据成功后更新数据
  */
 private void requestSuccessData() {
  mStepBeans.clear();//清空初始化数据
  String repOnse= "{\n" +
    " \"datas\": {\n" +
    "  \"day\": 3,\n" +
    "  \"myPoint\": 10890,\n" +
    "  \"signLog\": {\n" +
    "   \"content\": \"每日签到\",\n" +
    "   \"createTime\": \"2019-05-29 09:42:05\",\n" +
    "   \"familyId\": \"0\",\n" +
    "   \"id\": \"951660\",\n" +
    "   \"integral\": \"4\",\n" +
    "   \"logType\": \"3\",\n" +
    "   \"orderId\": \"0\",\n" +
    "   \"type\": \"1\",\n" +
    "   \"userId\": \"43431\"\n" +
    "  },\n" +
    "  \"signState\": true,\n" +
    "  \"userSingninList\": [\n" +
    "   {\n" +
    "    \"createTime\": \"2019-05-27 18:04:15\",\n" +
    "    \"day\": \"1\",\n" +
    "    \"familyId\": \"0\",\n" +
    "    \"id\": \"278904\",\n" +
    "    \"seriesDay\": \"1\",\n" +
    "    \"type\": \"0\",\n" +
    "    \"userId\": \"43431\"\n" +
    "   },\n" +
    "   {\n" +
    "    \"createTime\": \"2019-05-28 09:31:02\",\n" +
    "    \"day\": \"2\",\n" +
    "    \"familyId\": \"0\",\n" +
    "    \"id\": \"278905\",\n" +
    "    \"seriesDay\": \"2\",\n" +
    "    \"type\": \"0\",\n" +
    "    \"userId\": \"43431\"\n" +
    "   },\n" +
    "   {\n" +
    "    \"createTime\": \"2019-05-29 09:42:05\",\n" +
    "    \"day\": \"3\",\n" +
    "    \"familyId\": \"0\",\n" +
    "    \"id\": \"278907\",\n" +
    "    \"seriesDay\": \"3\",\n" +
    "    \"type\": \"0\",\n" +
    "    \"userId\": \"43431\"\n" +
    "   }\n" +
    "  ]\n" +
    " },\n" +
    " \"msg\": \"success!\",\n" +
    " \"ret\": 0\n" +
    "}";

  //解析后台请求数据
  SignListReq signListReq = new Gson().fromJson(reponse, SignListReq.class);
  if (signListReq.getRet() == 0) {
   rl_oval.setBackgroundResource(R.drawable.lianxusign_bg);
   text_sign.setText("已签到");
   text_lianxusign.setVisibility(View.VISIBLE);
   text_lianxusign.setText("连续" + signListReq.getDatas().getDay() + "天");

   setSignData(signListReq.getDatas());
  }

 }

 private void initView() {
  mStepView = findViewById(R.id.step_view);
  rl_oval = findViewById(R.id.rl_oval);
  text_sign = findViewById(R.id.text_sign);
  text_lianxusign = findViewById(R.id.text_lianxusign);

 }

 private void initData() {

  //初始化模拟请求后台数据
  String repOnse= "{\n" +
    " \"datas\": {\n" +
    "  \"day\": 2,\n" +
    "  \"myPoint\": 10886,\n" +
    "  \"signLog\": {\n" +
    "   \"content\": \"每日签到\",\n" +
    "   \"createTime\": \"2019-05-28 09:31:02\",\n" +
    "   \"familyId\": \"0\",\n" +
    "   \"id\": \"951656\",\n" +
    "   \"integral\": \"9\",\n" +
    "   \"logType\": \"3\",\n" +
    "   \"orderId\": \"0\",\n" +
    "   \"type\": \"1\",\n" +
    "   \"userId\": \"43431\"\n" +
    "  },\n" +
    "  \"signState\": true,\n" +
    "  \"userSingninList\": [\n" +
    "   {\n" +
    "    \"createTime\": \"2019-05-27 18:04:15\",\n" +
    "    \"day\": \"1\",\n" +
    "    \"familyId\": \"0\",\n" +
    "    \"id\": \"278904\",\n" +
    "    \"seriesDay\": \"1\",\n" +
    "    \"type\": \"0\",\n" +
    "    \"userId\": \"43431\"\n" +
    "   },\n" +
    "   {\n" +
    "    \"createTime\": \"2019-05-28 09:31:02\",\n" +
    "    \"day\": \"2\",\n" +
    "    \"familyId\": \"0\",\n" +
    "    \"id\": \"278905\",\n" +
    "    \"seriesDay\": \"2\",\n" +
    "    \"type\": \"0\",\n" +
    "    \"userId\": \"43431\"\n" +
    "   }\n" +
    "  ]\n" +
    " },\n" +
    " \"msg\": \"success!\",\n" +
    " \"ret\": 0\n" +
    "}";

  //解析后台请求数据
  SignListReq signListReq = new Gson().fromJson(reponse, SignListReq.class);
  if (signListReq.getRet() == 0) {
   setSignData(signListReq.getDatas());
  }
 }

 /**
  * 数据处理
  *
  * @param datas
  */
 private void setSignData(SignListReq.DatasBean datas) {

  //处理已签到的数据
  //先添加已签到的日期到集合中
  if (datas.getUserSingninList().size() != 0) {
   for (int i = 0; i 

4.主界面布局文件

<&#63;xml version="1.0" encoding="utf-8"&#63;>


 

  

   

   
  
 

 

5.签到bean

package com.sorgs.stepview.bean;

/**
 * description: 签到bean.
 */
public class StepBean {
 /**
  * 未完成
  */
 public static final int STEP_UNDO = -1;
 /**
  * 正在进行
  */
 public static final int STEP_CURRENT = 0;
 /**
  * 已完成
  */
 public static final int STEP_COMPLETED = 1;

 private int state;
 private int number;//0为不显示积分,非0为显示积分
 private String day;

 public StepBean(int state, int number, String day) {
  this.state = state;
  this.number = number;
  this.day = day;
 }


 public int getNumber() {
  return number;
 }

 public void setNumber(int number) {
  this.number = number;
 }

 public int getState() {
  return state;
 }

 public void setState(int state) {
  this.state = state;
 }

 public String getDay() {
  return day;
 }

 public void setDay(String day) {
  this.day = day;
 }
}

6.总结

该篇的功能是根据需求进行功能的处理,自定义View是实现了签到时的动画效果的,不过我们的需求不需要动画,所以这里就没调用演示,需要的可以自行调用

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。


推荐阅读
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 本文是关于自学Android的笔记,包括查看类的源码的方法,活动注册的必要性以及布局练习的重要性。通过学习本文,读者可以了解到在自学Android过程中的一些关键点和注意事项。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
author-avatar
louis
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有