主頁 > 移動端開發 > Android自定義實作按周簽到打卡功能

Android自定義實作按周簽到打卡功能

2021-02-03 11:10:11 移動端開發

之前實作過《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"即可獲取,


小編整理了一份Android電子書籍,需要的童鞋關注底部公眾號(longxuanzhigu)回復:“e_books” 即可獲取哦!
在這里插入圖片描述

以下是個人公眾號(longxuanzhigu),之后發布的文章會同步到該公眾號,方便交流學習Android知識及分享個人愛好文章:

在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/255927.html

標籤:其他

上一篇:使用Kotlin+協程+MVVM+Jetpack搭建快速開發框架

下一篇:Fragivity中對Fragment生命周期的優化處理

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more