• Android开发之打卡功能



    此篇实现每日打卡功能,有兴趣的小伙伴可以试试。
    老规矩,直接上代码!

    一、效果图

    在这里插入图片描述

    二、项目结构

    在这里插入图片描述

    三、布局文件(activity_main)

    在这里插入图片描述

    <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"
        android:background="#ffffffff"
        tools:context=".MainActivity" >
    
        <LinearLayout
            android:id="@+id/ll_popup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffeeeeee"
            android:orientation="vertical" >
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="10dp"
                android:background="#586771" >
    
                <TextView
                    android:id="@+id/popupwindow_calendar_month"
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:background="#586771"
                    android:gravity="center"
                    android:textColor="#aa564b4b"
                    android:textSize="18sp" />
            RelativeLayout>
    
            <com.example.SignCalendar
                android:id="@+id/popupwindow_calendar"
                android:layout_width="match_parent"
                android:layout_height="320dp"
                android:clickable="false" >
            com.example.SignCalendar>
    
            <Button
                android:id="@+id/btn_signIn"
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="20dp"
                android:background="@drawable/btn_sign_bg_selector"
                android:text="打卡"
                android:textColor="@android:color/white"
                android:textSize="16sp" />
        LinearLayout>
    
    RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    四、drawable中新建btn_sign_bg_selector.xml

    
    <selector xmlns:android="http://schemas.android.com/apk/res/android" >
        <item android:drawable="@drawable/btn_sign_bg_enable" android:state_enabled="true"/>
        <item  android:drawable="@drawable/btn_sign_bg_unable"/>
    selector>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    五、drawable中新建btn_sign_bg_enable.xml

    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle"
        >
        <solid android:color="#FF4F14"/>
        <corners android:radius="5dp"/>
    
    shape>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    六、drawable中新建btn_sign_bg_unable.xml

    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle"
        >
        <solid android:color="#CCCCCC"/>
        <corners android:radius="5dp"/>
    
    shape>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    七、drawable中新建bg_sign_today.xml

    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle"
        >
        <stroke android:width="1px" android:color="#FF4F14"/>
        <solid android:color="@android:color/transparent"/>
    
    shape>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    八、res包下新建anim包

    1.anim中新建push_left_in.xml

    
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="100%p"
            android:toXDelta="0"
            android:duration="400"/>
        <alpha
            android:fromAlpha="0.0"
            android:toAlpha="1.0"
            android:duration="400" />
    set>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.anim中新建push_left_out.xml

    
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="0"
            android:toXDelta="-100%p"
            android:duration="400"/>
        <alpha
            android:fromAlpha="1.0"
            android:toAlpha="0.0"
            android:duration="400" />
    set>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.anim中新建push_right_in.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="-100%p"
            android:toXDelta="0"
            android:duration="400"/>
        <alpha
            android:fromAlpha="0.0"
            android:toAlpha="1.0"
            android:duration="400" />
    set>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.anim中新建push_right_out.xml

    
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="0"
            android:toXDelta="100%p"
            android:duration="400"/>
        <alpha
            android:fromAlpha="1.0"
            android:toAlpha="1.0"
            android:duration="400" />
    set>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    九、drawable中图片

    1.calendar_date_focused.png

    在这里插入图片描述

    2.calendar_bg_tag.png

    在这里插入图片描述

    3.calendar_day_bg.9.png

    在这里插入图片描述

    十、res包下的values包下新建dimens.xml

    <resources>
    
        
        <dimen name="activity_horizontal_margin">16dpdimen>
        <dimen name="activity_vertical_margin">16dpdimen>
        <dimen name="historyscore_tb">10dpdimen>
    resources>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    十一、主java文件(MainActivity)

    package com.example;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    
    import com.example.R;
    import com.example.SignCalendar.OnCalendarDateChangedListener;
    
    public class MainActivity extends Activity {
    
        private String date = null;// 设置默认选中的日期  格式为 “2014-04-05” 标准DATE格式
        private TextView popupwindow_calendar_month;
        private SignCalendar calendar;
        private Button btn_signIn;
        private List<String> list = new ArrayList<String>(); //设置标记列表
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
            popupwindow_calendar_month = (TextView) findViewById(R.id.popupwindow_calendar_month);
            btn_signIn = (Button) findViewById(R.id.btn_signIn);
            calendar = (SignCalendar) findViewById(R.id.popupwindow_calendar);
            popupwindow_calendar_month.setText(calendar.getCalendarYear() + "年"
                    + calendar.getCalendarMonth() + "月");
            if (null != date) {
    
                int years = Integer.parseInt(date.substring(0,
                        date.indexOf("-")));
                int month = Integer.parseInt(date.substring(
                        date.indexOf("-") + 1, date.lastIndexOf("-")));
                popupwindow_calendar_month.setText(years + "年" + month + "月");
    
                calendar.showCalendar(years, month);
                calendar.setCalendarDayBgColor(date,
                        R.drawable.calendar_date_focused);
            }
    
            list.add("2015-11-10");
            list.add("2015-11-02");
            calendar.addMarks(list, 0);
            btn_signIn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Date today= calendar.getThisday();
                    calendar.addMark(today, 0);
                    HashMap<String, Integer> bg = new HashMap<String, Integer>();
                    calendar.setCalendarDayBgColor(today, R.drawable.bg_sign_today);
                    btn_signIn.setText("今日已签,明日继续");
                    btn_signIn.setEnabled(false);
                }
            });
            //监听所选中的日期
    //		calendar.setOnCalendarClickListener(new OnCalendarClickListener() {
    //
    //			public void onCalendarClick(int row, int col, String dateFormat) {
    //				int month = Integer.parseInt(dateFormat.substring(
    //						dateFormat.indexOf("-") + 1,
    //						dateFormat.lastIndexOf("-")));
    //
    //				if (calendar.getCalendarMonth() - month == 1//跨年跳转
    //						|| calendar.getCalendarMonth() - month == -11) {
    //					calendar.lastMonth();
    //
    //				} else if (month - calendar.getCalendarMonth() == 1 //跨年跳转
    //						|| month - calendar.getCalendarMonth() == -11) {
    //					calendar.nextMonth();
    //
    //				} else {
    //					list.add(dateFormat);
    //					calendar.addMarks(list, 0);
    //					calendar.removeAllBgColor();
    //					calendar.setCalendarDayBgColor(dateFormat,
    //							R.drawable.calendar_date_focused);
    //					date = dateFormat;//最后返回给全局 date
    //				}
    //			}
    //		});
    
            //监听当前月份
            calendar.setOnCalendarDateChangedListener(new OnCalendarDateChangedListener() {
                public void onCalendarDateChanged(int year, int month) {
                    popupwindow_calendar_month
                            .setText(year + "年" + month + "月");
                }
            });
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    十二、SignCalendar

    package com.example;
    
    import java.util.Calendar;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import android.content.Context;
    import android.content.res.Resources;
    import android.graphics.Color;
    import android.util.AttributeSet;
    import android.view.GestureDetector;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.ViewFlipper;
    
    /**
     *
     *
     * @author sxc 类说明:
     */
    @SuppressWarnings("deprecation")
    public class SignCalendar extends ViewFlipper implements
            android.view.GestureDetector.OnGestureListener {
        public static final int COLOR_BG_WEEK_TITLE = Color.parseColor("#ff999999"); // 星期标题背景颜色
        public static final int COLOR_TX_WEEK_TITLE = Color.parseColor("#ffcc3333"); // 星期标题文字颜色
        public static final int BEFORE_TODAY_BACKGROUND = Color.parseColor("#FFE4E4E4"); // 星期标题文字颜色
        // public static final int COLOR_TX_THIS_MONTH_DAY = Color.parseColor("#aa564b4b"); // 当前月日历数字颜色
        public static final int COLOR_TX_THIS_MONTH_DAY = Color.parseColor("#000000"); // 当前月日历数字颜色
        public static final int COLOR_TX_OTHER_MONTH_DAY = Color.parseColor("#ff999999"); // 其他月日历数字颜色
        public static final int COLOR_TX_THIS_DAY = Color.parseColor("#ff008000"); // 当天日历数字颜色
        public static final int COLOR_BG_THIS_DAY = Color.parseColor("#ffcccccc"); // 当天日历背景颜色
        public static final int COLOR_BG_CALENDAR = Color.parseColor("#ffeeeeee"); // 日历背景色
    
        private GestureDetector gd; // 手势监听器
        private Animation push_left_in; // 动画-左进
        private Animation push_left_out; // 动画-左出
        private Animation push_right_in; // 动画-右进
        private Animation push_right_out; // 动画-右出
    
        private int ROWS_TOTAL = 6; // 日历的行数
        private int COLS_TOTAL = 7; // 日历的列数
        private String[][] dates = new String[6][7]; // 当前日历日期
        private float tb;
    
        private OnCalendarClickListener onCalendarClickListener; // 日历翻页回调
        private OnCalendarDateChangedListener onCalendarDateChangedListener; // 日历点击回调
    
        private String[] weekday = new String[] {"日", "一", "二", "三", "四", "五", "六"}; // 星期标题
    
        private int calendarYear; // 日历年份
        private int calendarMonth; // 日历月份
        private Date thisday = new Date(); // 今天
        private Date calendarday; // 日历这个月第一天(1号)
    
        private LinearLayout firstCalendar; // 第一个日历
        private LinearLayout secondCalendar; // 第二个日历
        private LinearLayout currentCalendar; // 当前显示的日历
    
        private Map<String, Integer> marksMap = new HashMap<String, Integer>(); // 储存某个日子被标注(Integer
        // 为bitmap
        // res
        // id)
        private Map<String, Integer> dayBgColorMap = new HashMap<String, Integer>(); // 储存某个日子的背景色
    
        public SignCalendar(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public SignCalendar(Context context) {
            super(context);
            init();
        }
    
        private void init() {
            setBackgroundColor(COLOR_BG_CALENDAR);
            // 实例化收拾监听器
            gd = new GestureDetector(this.getContext(), this);
            // 初始化日历翻动动画
            push_left_in = AnimationUtils.loadAnimation(getContext(), R.anim.push_left_in);
            push_left_out = AnimationUtils.loadAnimation(getContext(), R.anim.push_left_out);
            push_right_in = AnimationUtils.loadAnimation(getContext(), R.anim.push_right_in);
            push_right_out = AnimationUtils.loadAnimation(getContext(), R.anim.push_right_out);
            // 初始化第一个日历
            firstCalendar = new LinearLayout(getContext());
            firstCalendar.setOrientation(LinearLayout.VERTICAL);
            firstCalendar.setLayoutParams(new LinearLayout.LayoutParams(-1, -1));
            // 初始化第二个日历
            secondCalendar = new LinearLayout(getContext());
            secondCalendar.setOrientation(LinearLayout.VERTICAL);
            secondCalendar.setLayoutParams(new LinearLayout.LayoutParams(-1, -1));
            // 设置默认日历为第一个日历
            currentCalendar = firstCalendar;
            // 加入ViewFlipper
            addView(firstCalendar);
            addView(secondCalendar);
            // 绘制线条框架
            drawFrame(firstCalendar);
            drawFrame(secondCalendar);
            // 设置日历上的日子(1号)
            calendarYear = thisday.getYear() + 1900;
            calendarMonth = thisday.getMonth();
            calendarday = new Date(calendarYear - 1900, calendarMonth, 1);
            // 填充展示日历
            setCalendarDate();
        }
    
        private void drawFrame(LinearLayout oneCalendar) {
    
            // 添加周末线性布局
            LinearLayout title = new LinearLayout(getContext());
            title.setBackgroundColor(COLOR_BG_WEEK_TITLE);
            title.setOrientation(LinearLayout.HORIZONTAL);
            LinearLayout.LayoutParams layout =
                    new LinearLayout.LayoutParams(MarginLayoutParams.MATCH_PARENT,
                            MarginLayoutParams.WRAP_CONTENT, 0.5f);
            Resources res = getResources();
            tb = res.getDimension(R.dimen.historyscore_tb);
            // layout.setMargins(0, 0, 0, (int) (tb * 1.2));
            title.setLayoutParams(layout);
            oneCalendar.addView(title);
    
            // 添加周末TextView
            for (int i = 0; i < COLS_TOTAL; i++) {
                TextView view = new TextView(getContext());
                view.setGravity(Gravity.CENTER);
                view.setPadding(0, 10, 0, 10);
                view.setText(weekday[i]);
                view.setTextColor(Color.WHITE);
                view.setLayoutParams(new LinearLayout.LayoutParams(0, -1, 1));
                title.addView(view);
            }
    
            // 添加日期布局
            LinearLayout content = new LinearLayout(getContext());
            content.setOrientation(LinearLayout.VERTICAL);
            content.setLayoutParams(new LinearLayout.LayoutParams(-1, 0, 7f));
            oneCalendar.addView(content);
    
            // 添加日期TextView
            for (int i = 0; i < ROWS_TOTAL; i++) {
                LinearLayout row = new LinearLayout(getContext());
                row.setOrientation(LinearLayout.HORIZONTAL);
                row.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1));
                content.addView(row);
                // 绘制日历上的列
                for (int j = 0; j < COLS_TOTAL; j++) {
                    RelativeLayout col = new RelativeLayout(getContext());
                    col.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1));
                    col.setBackgroundResource(R.drawable.calendar_day_bg);
                    // col.setBackgroundResource(R.drawable.sign_dialog_day_bg);
                    col.setClickable(false);
                    row.addView(col);
                    // 给每一个日子加上监听
                    col.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            ViewGroup parent = (ViewGroup) v.getParent();
                            int row = 0, col = 0;
    
                            // 获取列坐标
                            for (int i = 0; i < parent.getChildCount(); i++) {
                                if (v.equals(parent.getChildAt(i))) {
                                    col = i;
                                    break;
                                }
                            }
                            // 获取行坐标
                            ViewGroup pparent = (ViewGroup) parent.getParent();
                            for (int i = 0; i < pparent.getChildCount(); i++) {
                                if (parent.equals(pparent.getChildAt(i))) {
                                    row = i;
                                    break;
                                }
                            }
                            if (onCalendarClickListener != null) {
                                onCalendarClickListener.onCalendarClick(row, col, dates[row][col]);
                            }
                        }
                    });
                }
            }
        }
    
        /**
         * 填充日历(包含日期、标记、背景等)
         */
        private void setCalendarDate() {
            // 根据日历的日子获取这一天是星期几
            int weekday = calendarday.getDay();
            // 每个月第一天
            int firstDay = 1;
            // 每个月中间号,根据循环会自动++
            int day = firstDay;
            // 每个月的最后一天
            int lastDay = getDateNum(calendarday.getYear(), calendarday.getMonth());
            // 下个月第一天
            int nextMonthDay = 1;
            int lastMonthDay = 1;
    
            // 填充每一个空格
            for (int i = 0; i < ROWS_TOTAL; i++) {
                for (int j = 0; j < COLS_TOTAL; j++) {
                    // 这个月第一天不是礼拜天,则需要绘制上个月的剩余几天
                    if (i == 0 && j == 0 && weekday != 0) {
                        int year = 0;
                        int month = 0;
                        int lastMonthDays = 0;
                        // 如果这个月是1月,上一个月就是去年的12月
                        if (calendarday.getMonth() == 0) {
                            year = calendarday.getYear() - 1;
                            month = Calendar.DECEMBER;
                        } else {
                            year = calendarday.getYear();
                            month = calendarday.getMonth() - 1;
                        }
                        // 上个月的最后一天是几号
                        lastMonthDays = getDateNum(year, month);
                        // 第一个格子展示的是几号
                        int firstShowDay = lastMonthDays - weekday + 1;
                        // 上月
                        for (int k = 0; k < weekday; k++) {
                            lastMonthDay = firstShowDay + k;
                            RelativeLayout group = getDateView(0, k);
                            group.setGravity(Gravity.CENTER);
                            TextView view = null;
                            if (group.getChildCount() > 0) {
                                view = (TextView) group.getChildAt(0);
                            } else {
                                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-1, -1);
                                view = new TextView(getContext());
                                view.setLayoutParams(params);
                                view.setGravity(Gravity.CENTER);
                                group.addView(view);
                            }
                            view.setText(Integer.toString(lastMonthDay));
                            view.setTextColor(COLOR_TX_OTHER_MONTH_DAY);
                            dates[0][k] = format(new Date(year, month, lastMonthDay));
                            // 设置日期背景色
                            if (dayBgColorMap.get(dates[0][k]) != null) {
                                view.setBackgroundResource(dayBgColorMap.get(dates[0][k]));
                            } else {
                                view.setBackgroundColor(Color.TRANSPARENT);
                            }
                            // 设置标记
                            setMarker(group, 0, k);
                        }
                        j = weekday - 1;
                        // 这个月第一天是礼拜天,不用绘制上个月的日期,直接绘制这个月的日期
                    } else {
                        RelativeLayout group = getDateView(i, j);
                        group.setGravity(Gravity.CENTER);
                        TextView view = null;
                        if (group.getChildCount() > 0) {
                            view = (TextView) group.getChildAt(0);
                        } else {
                            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-1, -1);
                            view = new TextView(getContext());
                            view.setLayoutParams(params);
                            view.setGravity(Gravity.CENTER);
                            group.addView(view);
                        }
    
                        // 本月
                        if (day <= lastDay) {
                            dates[i][j] = format(new Date(calendarday.getYear(), calendarday.getMonth(), day));
                            view.setText(Integer.toString(day));
                            // 当天
                            if (thisday.getDate() == day && thisday.getMonth() == calendarday.getMonth()
                                    && thisday.getYear() == calendarday.getYear()) {
                                // view.setText("今天");
                                view.setTextColor(COLOR_TX_THIS_MONTH_DAY);
                                // view.setBackgroundResource(R.drawable.bg_sign_today);
                            } else if (thisday.getMonth() == calendarday.getMonth()) {
                                view.setTextColor(COLOR_TX_THIS_MONTH_DAY);
                            } else {
                                view.setTextColor(COLOR_TX_OTHER_MONTH_DAY);
                            }
                            // 上面首先设置了一下默认的"当天"背景色,当有特殊需求时,才给当日填充背景色
                            // 设置日期背景色
                            if (dayBgColorMap.get(dates[i][j]) != null) {
                                // view.setTextColor(Color.WHITE);
                                view.setBackgroundResource(dayBgColorMap.get(dates[i][j]));
                            }
                            // 设置标记
                            setMarker(group, i, j);
                            day++;
                            // 下个月
                        } else {
                            if (calendarday.getMonth() == Calendar.DECEMBER) {
                                dates[i][j] =
                                        format(new Date(calendarday.getYear() + 1, Calendar.JANUARY, nextMonthDay));
                            } else {
                                dates[i][j] =
                                        format(new Date(calendarday.getYear(), calendarday.getMonth() + 1, nextMonthDay));
                            }
                            view.setText(Integer.toString(nextMonthDay));
                            view.setTextColor(COLOR_TX_OTHER_MONTH_DAY);
                            // 设置日期背景色
                            if (dayBgColorMap.get(dates[i][j]) != null) {
                                // view.setBackgroundResource(dayBgColorMap
                                // .get(dates[i][j]));
                            } else {
                                view.setBackgroundColor(Color.TRANSPARENT);
                            }
                            // 设置标记
                            setMarker(group, i, j);
                            nextMonthDay++;
                        }
                    }
                }
            }
        }
    
        /**
         * onClick接口回调
         */
        public interface OnCalendarClickListener {
            void onCalendarClick(int row, int col, String dateFormat);
        }
    
        /**
         * ondateChange接口回调
         */
        public interface OnCalendarDateChangedListener {
            void onCalendarDateChanged(int year, int month);
        }
    
        /**
         * 根据具体的某年某月,展示一个日历
         *
         * @param year
         * @param month
         */
        public void showCalendar(int year, int month) {
            calendarYear = year;
            calendarMonth = month - 1;
            calendarday = new Date(calendarYear - 1900, calendarMonth, 1);
            setCalendarDate();
        }
    
        /**
         * 根据当前月,展示一个日历
         *
         */
        public void showCalendar() {
            Date now = new Date();
            calendarYear = now.getYear() + 1900;
            calendarMonth = now.getMonth();
            calendarday = new Date(calendarYear - 1900, calendarMonth, 1);
            setCalendarDate();
        }
    
        /**
         * 下一月日历
         */
        public synchronized void nextMonth() {
            // 改变日历上下顺序
            if (currentCalendar == firstCalendar) {
                currentCalendar = secondCalendar;
            } else {
                currentCalendar = firstCalendar;
            }
            // 设置动画
            setInAnimation(push_left_in);
            setOutAnimation(push_left_out);
            // 改变日历日期
            if (calendarMonth == Calendar.DECEMBER) {
                calendarYear++;
                calendarMonth = Calendar.JANUARY;
            } else {
                calendarMonth++;
            }
            calendarday = new Date(calendarYear - 1900, calendarMonth, 1);
            // 填充日历
            setCalendarDate();
            // 下翻到下一月
            showNext();
            // 回调
            if (onCalendarDateChangedListener != null) {
                onCalendarDateChangedListener.onCalendarDateChanged(calendarYear, calendarMonth + 1);
            }
        }
    
        /**
         * 上一月日历
         */
        public synchronized void lastMonth() {
            if (currentCalendar == firstCalendar) {
                currentCalendar = secondCalendar;
            } else {
                currentCalendar = firstCalendar;
            }
            setInAnimation(push_right_in);
            setOutAnimation(push_right_out);
            if (calendarMonth == Calendar.JANUARY) {
                calendarYear--;
                calendarMonth = Calendar.DECEMBER;
            } else {
                calendarMonth--;
            }
            calendarday = new Date(calendarYear - 1900, calendarMonth, 1);
            setCalendarDate();
            showPrevious();
            if (onCalendarDateChangedListener != null) {
                onCalendarDateChangedListener.onCalendarDateChanged(calendarYear, calendarMonth + 1);
            }
        }
    
        /**
         * 获取日历当前年份
         */
        public int getCalendarYear() {
            return calendarday.getYear() + 1900;
        }
    
        /**
         * 获取日历当前月份
         */
        public int getCalendarMonth() {
            return calendarday.getMonth() + 1;
        }
    
        /**
         * 在日历上做一个标记
         *
         * @param date 日期
         * @param id bitmap res id
         */
        public void addMark(Date date, int id) {
            addMark(format(date), id);
        }
    
        /**
         * 在日历上做一个标记
         *
         * @param date 日期
         * @param id bitmap res id
         */
        public void addMark(String date, int id) {
            marksMap.put(date, id);
            setCalendarDate();
        }
    
        /**
         * 在日历上做一组标记
         *
         * @param date 日期
         * @param id bitmap res id
         */
        public void addMarks(Date[] date, int id) {
            for (int i = 0; i < date.length; i++) {
                marksMap.put(format(date[i]), id);
            }
            setCalendarDate();
        }
    
        /**
         * 在日历上做一组标记
         *
         * @param date 日期
         * @param id bitmap res id
         */
        public void addMarks(List<String> date, int id) {
            for (int i = 0; i < date.size(); i++) {
                marksMap.put(date.get(i), id);
            }
            setCalendarDate();
        }
    
        /**
         * 移除日历上的标记
         */
        public void removeMark(Date date) {
            removeMark(format(date));
        }
    
        /**
         * 移除日历上的标记
         */
        public void removeMark(String date) {
            marksMap.remove(date);
            setCalendarDate();
        }
    
        /**
         * 移除日历上的所有标记
         */
        public void removeAllMarks() {
            marksMap.clear();
            setCalendarDate();
        }
    
        /**
         * 设置日历具体某个日期的背景色
         *
         * @param date
         * @param color
         */
        public void setCalendarDayBgColor(Date date, int color) {
            setCalendarDayBgColor(format(date), color);
        }
    
        /**
         * 设置日历具体某个日期的背景色
         *
         * @param date
         * @param color
         */
        public void setCalendarDayBgColor(String date, int color) {
            dayBgColorMap.put(date, color);
            setCalendarDate();
        }
    
        /**
         * 设置日历一组日期的背景色
         *
         * @param date
         * @param color
         */
        public void setCalendarDaysBgColor(List<String> date, int color) {
            for (int i = 0; i < date.size(); i++) {
                dayBgColorMap.put(date.get(i), color);
            }
            setCalendarDate();
        }
    
        /**
         * 设置日历一组日期的背景色
         *
         * @param date
         * @param color
         */
        public void setCalendarDayBgColor(String[] date, int color) {
            for (int i = 0; i < date.length; i++) {
                dayBgColorMap.put(date[i], color);
            }
            setCalendarDate();
        }
    
        /**
         * 移除日历具体某个日期的背景色
         */
        public void removeCalendarDayBgColor(Date date) {
            removeCalendarDayBgColor(format(date));
        }
    
        /**
         * 移除日历具体某个日期的背景色
         *
         */
        public void removeCalendarDayBgColor(String date) {
            dayBgColorMap.remove(date);
            setCalendarDate();
        }
    
        /**
         * 移除日历具体某个日期的背景色
         *
         */
        public void removeAllBgColor() {
            dayBgColorMap.clear();
            setCalendarDate();
        }
    
        /**
         * 根据行列号获得包装每一个日子的LinearLayout
         *
         * @return
         */
        public String getDate(int row, int col) {
            return dates[row][col];
        }
    
        /**
         * 某天是否被标记了
         *
         * @return
         */
        public boolean hasMarked(String date) {
            return marksMap.get(date) == null ? false : true;
        }
    
        /**
         * 清除所有标记以及背景
         */
        public void clearAll() {
            marksMap.clear();
            dayBgColorMap.clear();
        }
    
        /***********************************************
         *
         * private methods
         *
         **********************************************/
        // 设置标记
        private void setMarker(RelativeLayout group, int i, int j) {
            int childCount = group.getChildCount();
            if (marksMap.get(dates[i][j]) != null) {
                if (childCount < 2) {
                    RelativeLayout.LayoutParams params =
                            new RelativeLayout.LayoutParams((int) (tb * 0.7), (int) (tb * 0.7));
                    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                    params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
                    params.setMargins(0, 0, 1, 1);
                    ImageView markView = new ImageView(getContext());
                    markView.setImageResource(marksMap.get(dates[i][j]));
                    markView.setLayoutParams(params);
                    markView.setBackgroundResource(R.drawable.calendar_bg_tag);
                    group.addView(markView);
                }
            } else {
                if (childCount > 1) {
                    group.removeView(group.getChildAt(1));
                }
            }
    
        }
    
        /**
         * 计算某年某月有多少天
         *
         * @param year
         * @param month
         * @return
         */
        private int getDateNum(int year, int month) {
            Calendar time = Calendar.getInstance();
            time.clear();
            time.set(Calendar.YEAR, year + 1900);
            time.set(Calendar.MONTH, month);
            return time.getActualMaximum(Calendar.DAY_OF_MONTH);
        }
    
        /**
         * 根据行列号获得包装每一个日子的LinearLayout
         *
         * @param row
         * @param col
         * @return
         */
        private RelativeLayout getDateView(int row, int col) {
            return (RelativeLayout) ((LinearLayout) ((LinearLayout) currentCalendar.getChildAt(1))
                    .getChildAt(row)).getChildAt(col);
        }
    
        /**
         * 将Date转化成字符串->2013-3-3
         */
        private String format(Date d) {
            return addZero(d.getYear() + 1900, 4) + "-" + addZero(d.getMonth() + 1, 2) + "-"
                    + addZero(d.getDate(), 2);
        }
    
        // 2或4
        private static String addZero(int i, int count) {
            if (count == 2) {
                if (i < 10) {
                    return "0" + i;
                }
            } else if (count == 4) {
                if (i < 10) {
                    return "000" + i;
                } else if (i < 100 && i > 10) {
                    return "00" + i;
                } else if (i < 1000 && i > 100) {
                    return "0" + i;
                }
            }
            return "" + i;
        }
    
        /***********************************************
         *
         * Override methods
         *
         **********************************************/
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (gd != null) {
                if (gd.onTouchEvent(ev))
                    return true;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        public boolean onTouchEvent(MotionEvent event) {
            return this.gd.onTouchEvent(event);
        }
    
        public boolean onDown(MotionEvent e) {
            return false;
        }
    
        public void onShowPress(MotionEvent e) {}
    
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
    
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }
    
        public void onLongPress(MotionEvent e) {}
    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            // 向左/上滑动
            if (e1.getX() - e2.getX() > 20) {
                nextMonth();
            }
            // 向右/下滑动
            else if (e1.getX() - e2.getX() < -20) {
                lastMonth();
            }
            return false;
        }
    
        /***********************************************
         *
         * get/set methods
         *
         **********************************************/
    
        public OnCalendarClickListener getOnCalendarClickListener() {
            return onCalendarClickListener;
        }
    
        public void setOnCalendarClickListener(OnCalendarClickListener onCalendarClickListener) {
            this.onCalendarClickListener = onCalendarClickListener;
        }
    
        public OnCalendarDateChangedListener getOnCalendarDateChangedListener() {
            return onCalendarDateChangedListener;
        }
    
        public void setOnCalendarDateChangedListener(
                OnCalendarDateChangedListener onCalendarDateChangedListener) {
            this.onCalendarDateChangedListener = onCalendarDateChangedListener;
        }
    
        public Date getThisday() {
            return thisday;
        }
    
        public void setThisday(Date thisday) {
            this.thisday = thisday;
        }
    
        public Map<String, Integer> getDayBgColorMap() {
            return dayBgColorMap;
        }
    
        public void setDayBgColorMap(Map<String, Integer> dayBgColorMap) {
            this.dayBgColorMap = dayBgColorMap;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769

    十三、资源下载地址:Android开发之打卡功能

    好了,一个简单的打卡器就做成了,还有不懂的欢迎交流😊😊😊

  • 相关阅读:
    Java题目详解——牛客网JZ31.栈的压入,弹出序列
    二叉搜索树的实现
    一图读懂TWT
    React_Fragments
    libcurl Socks5 堆缓冲区溢出漏洞(CVE-2023-38545)详细分析
    30 位学者合力发表 Nature 综述,10 年回顾解构 AI 如何重塑科研范式
    RPA在财务预测和分析中的应用
    LoRa知识点记录
    QT系列教程(11) TextEdit实现Qt 文本高亮
    30岁+文转码程序媛求职路复盘:也算是逆袭了!
  • 原文地址:https://blog.csdn.net/qq_61963074/article/details/126482698