乐趣区

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<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. 主程序逻辑处理

/**
 * 一周签到规则:* 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<StepBean> 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 < datas.getUserSingninList().size(); i++) {
                // 时间格式:2019-05-27 18:04:15
                String createTime = datas.getUserSingninList().get(i).getCreateTime();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date d1 = null;
                try {d1 = df.parse(createTime);
                } catch (ParseException e) {e.printStackTrace();
                }
                String timeString = df.format(d1);
                // 获取日期的月、日
                String[] timeList = timeString.split(" ");
                String[] split = timeList[0].split("-");
                String month = split[1];// 月
                String day = split[2];// 日

                // 判断是否需要显示积分图标,number 表示 -- 0 为不显示积分,非 0 为显示积分
                if (datas.getSignLog() != null && datas.getUserSingninList().get(i).getCreateTime().equals(datas.getSignLog().getCreateTime())) {mStepBeans.add(new StepBean(StepBean.STEP_COMPLETED, Integer.parseInt(datas.getSignLog().getIntegral()), month + "." + day));
                } else {mStepBeans.add(new StepBean(StepBean.STEP_COMPLETED, 0, month + "." + day));
                }
            }
        }

        // 添加未签到的数据,填充为最近一周数据
        if (mStepBeans.size() < 7) {

            // 获取当前时间的月日
            Calendar now = Calendar.getInstance();
            int currentMonth = now.get(Calendar.MONTH) + 1;// 当月
            int currentDay = now.get(Calendar.DAY_OF_MONTH);// 当天
            String currentTime = setData(currentMonth) + "." + setData(currentDay);

            // 后台有签到集合数据
            if (datas.getUserSingninList().size() != 0) {String createTime = datas.getUserSingninList().get(datas.getUserSingninList().size() - 1).getCreateTime();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date d1 = null;
                try {d1 = df.parse(createTime);
                } catch (ParseException e) {e.printStackTrace();
                }
                String timeString = df.format(d1);
                String[] timeList = timeString.split(" ");
                String[] split = timeList[0].split("-");
                String month = split[1];// 月
                String day = split[2];// 日

                for (int i = mStepBeans.size(); i < 7; i++) {int parseInt = Integer.parseInt(day) + i - 1;
                    // 判断累积的天数是否超过当月的总天数
                    if (parseInt <= getDayOfMonth()) {String time = setData(Integer.parseInt(month)) + "." + setData(parseInt);
                        if (currentTime.equals(time)) {mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time));
                        } else {mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time));
                        }
                    } else {String time = setData((Integer.parseInt(month) + 1)) + "." + setData(parseInt - getDayOfMonth());
                        if (currentTime.equals(time)) {mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time));
                        } else {mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time));
                        }
                    }
                }
            } else {// 后台没有签到集合数据,没有的话从当天时间开始添加未来一周的日期数据
                for (int i = 0; i < 7; i++) {
                    int parseInt = currentDay + i;
                    // 判断累积的天数是否超过当月的总天数
                    if (parseInt <= getDayOfMonth()) {String time = setData(currentMonth) + "." + setData(parseInt);
                        if (currentTime.equals(time)) {mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time));
                        } else {mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time));
                        }
                    } else {String time = setData((currentMonth + 1)) + "." + setData(parseInt - getDayOfMonth());
                        if (currentTime.equals(time)) {mStepBeans.add(new StepBean(StepBean.STEP_CURRENT, 0, time));
                        } else {mStepBeans.add(new StepBean(StepBean.STEP_UNDO, 0, time));
                        }
                    }
                }
            }
        }

        mStepView.setStepNum(mStepBeans);
    }

    /**
     * 获取最大天数
     *
     * @return
     */
    public int getDayOfMonth() {Calendar aCalendar = Calendar.getInstance(Locale.CHINA);
        int day = aCalendar.getActualMaximum(Calendar.DATE);
        return day;
    }

    /**
     * 日月份处理
     *
     * @param day
     * @return
     */
    public String setData(int day) {
        String time = "";
        if (day < 10) {time = "0" + day;} else {time = "" + day;}

        return time;
    }
}

4. 主界面布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.activity.MainActivity">

    <RelativeLayout
        android:id="@+id/rl_oval"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_marginTop="150dp"
        android:layout_centerHorizontal="true"
        android:background="@drawable/sign_bg">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="vertical">

            <TextView
                android:id="@+id/text_sign"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="签到"
                android:textColor="#fff"
                android:layout_gravity="center_horizontal"
                android:textSize="16sp" />

            <TextView
                android:id="@+id/text_lianxusign"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连续 3 天"
                android:textColor="#fff"
                android:visibility="gone"
                android:layout_gravity="center_horizontal"
                android:textSize="12sp" />
        </LinearLayout>
    </RelativeLayout>

    <com.sorgs.stepview.ui.widget.StepsView
        android:id="@+id/step_view"
        android:layout_below="@id/rl_oval"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="15dp"
        android:layout_width="match_parent"
        android:layout_height="77dp" />
</RelativeLayout>

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 是实现了签到时的动画效果的,不过我们的需求不需要动画,所以这里就没调用演示,需要的可以自行调用

需要 Demo 源码的童鞋可以在底部的公众号回复:”StepView” 即可获取。


以下是个人公众号(longxuanzhigu),之后发布的文章会同步到该公众号,方便交流学习 Android 知识及分享个人爱好文章:

退出移动版