Android 实现签到足迹功能

UI 妹纸又给了个图叫我做,我一看是这样的:

我们首先把这个控件划分成 几个部分:

1.底下部分的直线 :

2.左右两边的半圆弧度 :

3.线上面的小图标 :

4.最后的文字说明 :

首先我们把线画出来,大概这个样子

我们这里根据一个月得总天数,和一条线上需要画七个图,计算出总共需要画出的线条数,以及画出左边和右边的弧度,根据当前线是单数还是双数,来计算出是否是左半边的弧度,还是右半边的弧度,以及是否是最后的一条线,因为最后一条线不需要画弧度。

代码如下:

    @Override
    protected void onDraw(Canvas canvas)
{
        paint.setColor(backColor);
        paint.setStrokeWidth(strokeWidth);
        int rowCount = (monthDays % 7 == 0 ? monthDays / 7 : monthDays / 7 + 1);
        int rowHeigh = height / (rowCount);
        int startX = 0 + rowHeigh / 2;
        int endX = width - rowHeigh / 2;
        int days = 0;

        for (int a = 0; a < rowCount; a++)
        {
            if (a + 1 == rowCount)
            {
                endX = (endX - startX) / 7 * (monthDays % 7) + checkBitmap.getWidth() / 2;
            }
            paint.setStrokeWidth(strokeWidth);
            int y = rowHeigh * a + rowHeigh / 2;
            canvas.drawLine(startX, y, endX, y, paint);

            paint.setColor(rashColor);
            paint.setStrokeWidth(1);
            canvas.drawLine(startX, y, endX, y, paint);
            // 这里是来判断,是否需要画出左半边还是右半边的半圆弧度?
            if (a % 2 != 0)
            {
                if (a + 1 != rowCount)
                {
                    drawLeftOrRightArc(true, canvas, 0 + strokeWidth, y, 0 + rowHeigh + strokeWidth, y + rowHeigh);
                }
            } else
            {
                if (a + 1 != rowCount)
                {
                    drawLeftOrRightArc(false, canvas, endX - rowHeigh / 2 - strokeWidth, y, endX + rowHeigh / 2 - strokeWidth, y + rowHeigh);
                }
            }
        }
    }

然后再在线上画出礼物数量

            // 这里是来判断,本次这根线上画出的礼物的点,以及顺序是顺画,还是倒画出。
            bitmapList.clear();
            for (int b = 0; b < (a + 1 == rowCount ? (monthDays % 7) : 7); b++)
            {
                days++;
                if (days <= signInCount)
                {
                    if (days == 3 || days == 8 || days == 14 || days == 21 || days == monthDays)
                    {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), openGiftBitmap);
                    } else
                    {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), checkBitmap);
                    }
                } else
                {
                    if (days == 3 || days == 8 || days == 14 || days == 21 || days == monthDays)
                    {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), closeGiftBitmap);
                    } else
                    {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), uncheckBitmap);
                    }
                }
            }

这里有一个需要注意的地方,就是,在线为双数的时候,这时候礼物的排列是需要反过来排列的,我这里使用了一个LinkedList来保存礼物的排列顺序,然后我们通过计算平均数,计算出每个礼物的位置。

    /**
     * 画出的按路线上的图片,勾选,礼物
     * @param bitmapList
     * @param startX
     * @param endX
     * @param y
     * @param canvas
     */
    private void drawImgs(List<Bitmap> bitmapList, float startX, float endX, float y, Canvas canvas)
{
        startX = startX - bitmapList.get(0).getWidth() / 2;
        int count = bitmapList.size();
        float bitmap_width = (endX - startX) / (count - 1);
        for (int a = 0; a < count; a++)
        {
            Bitmap bitmap = bitmapList.get(a);
            canvas.drawBitmap(bitmap, startX + (bitmap_width * a), y - bitmap.getHeight() / 2, paint);
        }
    }

这里也有一个需要注意的地方,就是,当最后一条线是短的时候,这个时候,你的礼物的排列需要按照那条线的开始位置和结束位置来平均计算每个礼物的位置。

最后,我们在最后一条线最后的位置,画出文字

/**
     * 画出文字
     * @param canvas
     * @param y
     * @param x
     */
    private void drawText(Canvas canvas, float y, float x)
{
        int oldColor = paint.getColor();
        Paint.Style old_style = paint.getStyle();

        paint.setStyle(Paint.Style.FILL);
        paint.setColor(textColor);
        String drawText = "已累计签到"+signInCount+"天";
        paint.setTextSize(DensityUtil.sp2px(getContext(), 15));
        int textHeigh = getStringHeight(drawText);
        int textWidth = getStringWidth(drawText);
        canvas.drawText(drawText, x + textWidth/2, y + textHeigh / 2, paint);

        paint.setColor(oldColor);
        paint.setStyle(old_style);
    }

好了,这就是所有的思路。下面贴一下最新完整代码:

package com.sjl.keeplive.track;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.sjl.keeplive.R;

import java.util.LinkedList;
import java.util.List;

public class SignInView extends View {
    private int width, height;
    private int monthDays = 31;//本月有31天
    private Paint paint;
    private RectF oval = new RectF();
    private float strokeWidth = 10;
    private Bitmap checkBitmap, uncheckBitmap, closeGiftBitmap, openGiftBitmap;
    private int backColor = Color.parseColor("#C3DEEA"),
            rashColor = Color.parseColor("#B2CADB"),
            textColor = Color.parseColor("#60ADE5");
    private List<Bitmap> bitmapList = new LinkedList<>();
    private int signInCount = 9;

    public SignInView(Context context) {
        this(context, null);
    }

    public SignInView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SignInView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint = new Paint();
        paint.setAntiAlias(true);
        strokeWidth = DensityUtil.dip2px(6);
        checkBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_sign_in_check_img);
        uncheckBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_sign_in_uncheck_img);
        closeGiftBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_close_gift_img);
        openGiftBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_open_gift_img);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        height = MeasureSpec.getSize(heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 设置本月天数
     *
     * @param monthDays
     */
    public void setMonthDays(int monthDays) {
        this.monthDays = monthDays;
        if (monthDays == 0) {
            this.monthDays = 31;
        }
        postInvalidate();
    }

    /**
     * 设置一共签到了几天
     *
     * @param days
     */
    public void setProgress(int days) {
        this.signInCount = days;
        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        paint.setColor(backColor);
        paint.setStrokeWidth(strokeWidth);
        int rowCount = (monthDays % 7 == 0 ? monthDays / 7 : monthDays / 7 + 1);
        int rowHeigh = height / (rowCount);
        int startX = 0 + rowHeigh / 2;
        int endX = width - rowHeigh / 2;
        int days = 0;

        for (int a = 0; a < rowCount; a++) {
            if (a + 1 == rowCount) {
                endX = (endX - startX) / 7 * (monthDays % 7 == 0 ? 7 : (monthDays % 7)) + checkBitmap.getWidth() / 2;
            }
            paint.setStrokeWidth(strokeWidth);
            int y = rowHeigh * a + rowHeigh / 2;
            canvas.drawLine(startX, y, endX, y, paint);

            paint.setColor(rashColor);
            paint.setStrokeWidth(1);
            canvas.drawLine(startX, y, endX, y, paint);
            // 这里是来判断,是否需要画出左半边还是右半边的半圆弧度?
            if (a % 2 != 0) {
                if (a + 1 != rowCount) {
                    drawLeftOrRightArc(true, canvas, 0 + strokeWidth, y, 0 + rowHeigh + strokeWidth, y + rowHeigh);
                }
            } else {
                if (a + 1 != rowCount) {
                    drawLeftOrRightArc(false, canvas, endX - rowHeigh / 2 - strokeWidth, y, endX + rowHeigh / 2 - strokeWidth, y + rowHeigh);
                }
            }

            // 这里是来判断,本次这根线上画出的礼物的点,以及顺序是顺画,还是倒画出。
            bitmapList.clear();
            int lastDay = (monthDays % 7) == 0 ? 7 : (monthDays % 7);
            for (int b = 0; b < (a + 1 == rowCount ? (lastDay) : 7); b++) {
                days++;
                if (days <= signInCount) {
                    if (days == 3 || days == 8 || days == 14 || days == 21 || days == monthDays) {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), openGiftBitmap);
                    } else {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), checkBitmap);
                    }
                } else {
                    if (days == 3 || days == 8 || days == 14 || days == 21 || days == monthDays) {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), closeGiftBitmap);
                    } else {
                        bitmapList.add(a % 2 != 0 ? 0 : bitmapList.size(), uncheckBitmap);
                    }
                }
            }

            drawImgs(bitmapList, startX, endX, y, canvas);
        }
        super.onDraw(canvas);
    }

    /**
     * 画出的按路线上的图片,勾选,礼物
     *
     * @param bitmapList
     * @param startX
     * @param endX
     * @param y
     * @param canvas
     */
    private void drawImgs(List<Bitmap> bitmapList, float startX, float endX, float y, Canvas canvas) {
        if (!bitmapList.isEmpty()) {
            startX = startX - bitmapList.get(0).getWidth() / 2;
            int count = bitmapList.size();
            float bitmap_width = (endX - startX) / (count - 1);
            for (int a = 0; a < count; a++) {
                Bitmap bitmap = bitmapList.get(a);
                canvas.drawBitmap(bitmap, startX + (bitmap_width * a), y - bitmap.getHeight() / 2, paint);
            }
        }
    }

    /**
     * 这里画出左边半圆弧,还是右边半圆弧
     *
     * @param isLeft
     * @param canvas
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    private void drawLeftOrRightArc(boolean isLeft, Canvas canvas, float left, float top, float right, float bottom) {
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(backColor);

        if (isLeft) {
            paint.setStyle(Paint.Style.STROKE);
            oval.setEmpty();
            oval.set(left, top, right, bottom);
            canvas.drawArc(oval, 90, 180, false, paint);
            paint.setStrokeWidth(1);
            paint.setColor(rashColor);
            canvas.drawArc(oval, 90, 180, false, paint);
        } else {
            paint.setStyle(Paint.Style.STROKE);
            oval.setEmpty();
            oval.set(left, top, right, bottom);
            canvas.drawArc(oval, 270, 180, false, paint);

            paint.setStrokeWidth(1);
            paint.setColor(rashColor);

            canvas.drawArc(oval, 270, 180, false, paint);
        }
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(backColor);
    }
}

布局文件使用:

 <com.sjl.keeplive.track.SignInView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"/>

项目地址:

链接:https://pan.baidu.com/s/1IUh9og2T3IlxeXhaLLOKGg
提取码:thoc

由于demo集合比较多,单这篇看下面代码即可:

以上就是Android 实现签到足迹功能的详细内容,更多关于Android 签到功能的资料请关注我们其它相关文章!

(0)

相关推荐

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

    前言 之前实现过<Android可签到的日历控件>的功能,跟这篇一样都是实现签到打卡功能,这篇实现的是按月进行打卡做标识,本篇内容实现的按周进行签到打卡. 实现签到规则如下: 1.连续签到7天,即可获得额外积分奖励. 2.连续签到记录在第8天开始时将清零重新计算. 3.如果中断签到,连续签到记录也将清零. 实现步骤: 1.效果图 2.自定义签到打卡View 3.主程序逻辑处理 4.主界面 5.签到bean 6.总结 实现过程: 1.效果图 2.自定义签到打卡View /** * descrip

  • Android简单实现app每月签到功能

    本文实例为大家分享了Android实现app每月签到功能的具体代码,供大家参考,具体内容如下 先上一张效果图: 其中这些签到的效果图是在网上找的,然后重要用到的控件就是 GridvVew 了, 代码很简单,只有3个代码文件: MainActivity.class 文件 package zhanghuan.cn.checkdesign; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import

  • Android 百度地图定位实现仿钉钉签到打卡功能的完整代码

    导语 本章根据百度地图API,实现仿钉钉打卡功能.用到了基础地图.覆盖物.定位图层.陀螺仪方法.悬浮信息弹框. 百度地图API地址  :Android 地图SDK 请先注册注册百度账号和获取密钥,并实现地图显示出来.(注意:密钥.权限要设置) 另外,我得说明本章所下载官方Demo 和 导入的jar包和so文件.自定义下载即可,如下图: 接下来,一起看实现效果. 源码Git地址:BaiduMapApp 效果图 实现代码·三步骤 第一步:基础地图和方向传感器 类先实现方向传感器 implements

  • Android可签到日历控件的实现方法

    最近在公司的功能需求中,需要实现可以签到的日历,签到后在签到过的日期做标志.本功能参考了网上一些大神的日历控件,在此基础上进行修改,已满足本公司的需求,现已完成,记录一下. 布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_wi

  • Android积分签到上移消失动画效果

    还记得以前在某云的时候,有次需求是一个积分签到,要求点击签到按钮然后有一个动画效果,比如+30积分然后慢慢往上移动在消失.那会不会做就想着改下需求,直接去掉了动画效果,而今时隔很久又遇到同样的问题,比较蛋疼的是我清楚记得当时做过这个功能,但是自己没有做出来,当然现在做还是不会.自己当年省写的代码含泪也要补上.这次吸取教训,实现这个效果. 大致思路:动画部分,由一个垂直的平移和一个透明度变化的两个动画组成.然后通过AnimationSet将两个动画添加到集合,然后开始播放动画. 更新UI部分,用的

  • Android实现带签到赢积分功能的日历

    Android实现点击签到按钮直接签到,弹出dialog,先上效果图 demo是利用gridview实现的,现附上布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent&qu

  • Android基于AccessibilityService制作的钉钉自动签到程序代码

    前两天公司开始宣布要使用阿里钉钉来签到啦!!!~~这就意味着,我必须老老实实每天按时签到上班下班了,这真是一个悲伤的消息,可是!!!!那么机智(lan)的我,怎么可能就这么屈服!!!阿里钉钉签到,说到底不就是手机软件签到吗?我就是干移动开发的,做一个小应用每天自动签到不就行了:) 说干就干,首先分析一下,阿里钉钉的签到流程: 打开阿里钉钉->广告页停留2S左右->进入主页->点击"工作"tab->点击"签到"模块->进入签到页面(可能会

  • Android项目实战之百度地图地点签到功能

    前言:先写个简单的地点签到功能,如果日后有时间细写的话,会更加好好研究一下百度地图api,做更多逻辑判断. 这里主要是调用百度地图中的场景定位中的签到场景.通过官方文档进行api集成.通过GPS的定位功能,获取地理位置,时间,用户名进行存储.之后通过日历显示历史签到记录. 效果图: /**百度地图sdk**/ implementation files('libs/BaiduLBS_Android.jar') /**日历选择器**/ implementation 'com.prolificinte

  • Android 实现签到足迹功能

    UI 妹纸又给了个图叫我做,我一看是这样的: 我们首先把这个控件划分成 几个部分: 1.底下部分的直线 : 2.左右两边的半圆弧度 : 3.线上面的小图标 : 4.最后的文字说明 : 首先我们把线画出来,大概这个样子 我们这里根据一个月得总天数,和一条线上需要画七个图,计算出总共需要画出的线条数,以及画出左边和右边的弧度,根据当前线是单数还是双数,来计算出是否是左半边的弧度,还是右半边的弧度,以及是否是最后的一条线,因为最后一条线不需要画弧度. 代码如下: @Override protected

  • Android中Activity常用功能设置小结(包括全屏、横竖屏等)

    本文实例讲述了Android中Activity常用功能设置小结(包括全屏.横竖屏等).分享给大家供大家参考,具体如下: Activity全屏设置 方式1:AndroidManifest.xml 复制代码 代码如下: <activity android:name="myAcitivty"  android:theme="@android:style/Theme.NoTitleBar.Fullscreen" /> 方式2:代码实现 复制代码 代码如下: re

  • Android 获取随机验证码功能示例

    验证码功能在各大网站都能用到,下面小编通过实例代码给大家分享Android 获取随机验证码功能,具体代码如下所示: package cn.hk.image; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; impo

  • Android仿外卖购物车功能

    先看看效果图: 知识点分析 效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧 - 列表标题悬停 - 左右列表滑动时联动 - 添加商品时的抛物线动画 - 底部弹出购物车清单 - 数据的同步 另外就是实现效果的时候可能会遇到的几个坑... 布局很简单直接进入代码 1:列表标题悬停 现在做项目列表什么的基本抛弃了ListView改用RecyclerView,上篇博客中的标题悬停也是使用了一个RecyclerView的开源项目sticky-headers-recyclerview,不过写

  • Android Camera开发手电筒功能

    这是一个简单的运用Android Camera开发手电筒功能,AndroidManifest.xml文件的入口是startapp,这个文件没上传上来,大家可以自己写. flashlight.java package com.android.app; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.os.Bun

  • Android实现时间倒计时功能

    本文实例为大家分享了Android实现时间倒计时功能展示的具体代码,供大家参考,具体内容如下 效果展示 MainActivity(主页面代码) public class MainActivity extends Activity { private RelativeLayout countDown; // 倒计时 private TextView daysTv, hoursTv, minutesTv, secondsTv; private long mDay = 10; private long

  • Android中Listview点赞功能的实现

    最近这段时间一直在看Android,利用Listview去实现点赞功能,下面给大家介绍下基本思路. 基本思路: 进入界面–>获取数据–> 在Listview中显示–> 通过map集合(position,boolean)保存每一行是否被点击–> 利用实体类去保存相应的对象–> get/set方法进行相应值得改变–> 点击一次,相应的数量加1 只实现了点赞功能,踩和赞基本类似. 具体实现如下: 继承自BaseAdapter package com.gz.test_listv

  • Android实现微信支付功能

    开发Android APP微信支付功能,需要完成三个步骤:第一步生成预支付订单.第二步生成微信支付参数.第三步调起微信APP支付.除了需要审核通过的APP应用外,还需要获得微信支付接口权限,然后获取对应的商户号.API密钥,这两者缺一不可,并且在APP微信支付中使用 获得商户号.API密钥 在微信开放平台中查看审核通过的APP应用,是否申请支付功能,若已申请,登录微信支付|商户平台:http://pay.weixin.qq.com 查看对应的商户号.API密钥 >申请微信支付接口 >登录商户平

  • Android调用手机拍照功能的方法

    本文实例讲述了Android调用手机拍照功能的方法.分享给大家供大家参考.具体如下: 一.main.xml布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" andr

  • Android 实现截屏功能的实例

    Android 实现截屏功能的实例 实现代码: public class ScreenShot { // 获取指定Activity的截屏,保存到png文件 private static Bitmap takeScreenShot(Activity activity) { // View是你需要截图的View View view = activity.getWindow().getDecorView(); view.setDrawingCacheEnabled(true); view.buildD

随机推荐