package com.future.driver.utils.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * Created by zhouyou on 2016/7/25. * Class desc: *

* 自定义日历View,可多选 * * */ public class CalendarView extends View { // 列的数量 private static final int NUM_COLUMNS = 7; // 行的数量 private static final int NUM_ROWS = 6; /** * 可选日期数据 */ private List mOptionalDates = new ArrayList<>(); private int nowDay = 0; /** * 以选日期数据 */ private List mSelectedDates = new ArrayList<>(); /** * 异常日期数据 */ private List mErrorDates = new ArrayList<>(); // 分割线颜色 private int mDividerColor = Color.parseColor("#DEDEDE"); // 默认背景颜色和不可选背景色 private int mBgColor = Color.parseColor("#ffffff"); // 选中背景颜色 private int mSelectedColor = Color.parseColor("#F07207"); // 可选背景颜色 private int mAbleColor = Color.parseColor("#FFFFFF"); // 天数默认颜色 private int mDayNormalColor = Color.parseColor("#27282D"); //异常日期 private int mErrorColor = Color.parseColor("#FF5C5C"); // 天数不可选颜色 private int mDayNotOptColor = Color.parseColor("#BEBEC0"); // 天数选择后颜色 private int mDayPressedColor = Color.WHITE; // 天数字体大小 private int mDayTextSize = 14; // 是否可以被点击状态 private boolean mClickable = true; //是否单选 private boolean mSingle = true; private DisplayMetrics mMetrics; private Paint mPaint; private int mCurYear; private int mCurMonth; private int mCurDate; private int mSelYear; private int mSelMonth; private int mSelDate; private int mColumnSize; private int mRowSize; private int[][] mDays = new int[6][7]; // 当月一共有多少天 private int mMonthDays; // 当月第一天位于周几 private int mWeekNumber; public CalendarView(Context context) { super(context); init(); } public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 获取手机屏幕参数 mMetrics = getResources().getDisplayMetrics(); // 创建画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); // 获取当前日期 Calendar calendar = Calendar.getInstance(); mCurYear = calendar.get(Calendar.YEAR); mCurMonth = calendar.get(Calendar.MONTH); mCurDate = calendar.get(Calendar.DATE); setSelYTD(mCurYear, mCurMonth, mCurDate); nowDay = Integer.parseInt(getSelData(mCurYear, mCurMonth, mCurDate)); mSelectedDates.add(getSelData(mCurYear, mCurMonth, mCurDate)); } @Override protected void onDraw(Canvas canvas) { initSize(); // 绘制背景 mPaint.setColor(mBgColor); canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mPaint); // 设置绘制字体大小 mPaint.setTextSize(mDayTextSize * mMetrics.scaledDensity); // 绘制分割线 // mPaint.setColor(mDividerColor); // for (int i = 1;i= nowDay) { // 可选,继续判断是否是点击过的 if (!mSelectedDates.contains(getSelData(mSelYear, mSelMonth, mDays[row][column]))) { // 没有点击过,绘制默认背景 // canvas.drawBitmap(mBgNotOptBitmap, startX - (mBgNotOptBitmap.getWidth() / 3), startY - (mBgNotOptBitmap.getHeight() / 2), mPaint); mPaint.setColor(mAbleColor); canvas.drawRect(column * mColumnSize, row * mRowSize, column * mColumnSize + mColumnSize, row * mRowSize + mRowSize, mPaint); mPaint.setColor(mDayNormalColor); } else { // 点击过,绘制点击过的背景 // canvas.drawBitmap(mBgOptBitmap, startX - (mBgOptBitmap.getWidth() / 3), startY - (mBgOptBitmap.getHeight() / 2), mPaint); mPaint.setColor(mSelectedColor); // canvas.drawRect(column*mColumnSize,row*mRowSize,column*mColumnSize+mColumnSize,row*mRowSize+mRowSize,mPaint); canvas.drawCircle(column * mColumnSize + 0.5f * mColumnSize, row * mRowSize + 0.5f * mRowSize, 0.4f * mColumnSize, mPaint); mPaint.setColor(mDayPressedColor); } //是异常天数 if (mErrorDates.contains(getSelData(mSelYear, mSelMonth, mDays[row][column]))) { mPaint.setColor(mErrorColor); } // 绘制天数 canvas.drawText(dayStr, startX, startY, mPaint); } else { //是异常天数 if (mErrorDates.contains(getSelData(mSelYear, mSelMonth, mDays[row][column]))) { mPaint.setColor(mErrorColor); } else mPaint.setColor(mDayNotOptColor); canvas.drawText(dayStr, startX, startY, mPaint); } } } private int downX = 0, downY = 0; @Override public boolean onTouchEvent(MotionEvent event) { int eventCode = event.getAction(); switch (eventCode) { case MotionEvent.ACTION_DOWN: downX = (int) event.getX(); downY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: if (!mClickable) return true; int upX = (int) event.getX(); int upY = (int) event.getY(); if (Math.abs(upX - downX) < 10 && Math.abs(upY - downY) < 10) { performClick(); onClick((upX + downX) / 2, (upY + downY) / 2); } break; } return true; } public void setErrorDays(List errorDates){ this.mErrorDates = errorDates; invalidate(); } /** * 点击事件 */ private void onClick(int x, int y) { int row = y / mRowSize; int column = x / mColumnSize; setSelYTD(mSelYear, mSelMonth, mDays[row][column]); // 判断是否点击过 boolean isSelected = mSelectedDates.contains(getSelData(mSelYear, mSelMonth, mSelDate)); // 判断是否可以添加 boolean isCanAdd = Integer.parseInt(getSelData(mSelYear, mSelMonth, mDays[row][column])) >= nowDay; if (isSelected) { mSelectedDates.remove(getSelData(mSelYear, mSelMonth, mSelDate)); } else if (isCanAdd) { if (mSingle) mSelectedDates.clear(); mSelectedDates.add(getSelData(mSelYear, mSelMonth, mSelDate)); } invalidate(); if (mListener != null && isCanAdd) { // 执行回调 String dateStr = mSelYear + "-"; if (mSelMonth + 1 < 10) dateStr = dateStr + "0" + (mSelMonth + 1) + "-"; else dateStr = dateStr + (mSelMonth + 1) + "-"; if (mSelDate < 10) dateStr = dateStr + "0" + mSelDate; else dateStr = dateStr + mSelDate; mListener.onClickDateListener(dateStr); } } public String getCurrent() { String dateStr = mCurYear + "-"; if (mCurMonth + 1 < 10) dateStr = dateStr + "0" + (mCurMonth + 1) + "-"; else dateStr = dateStr + (mCurMonth + 1) + "-"; if (mCurDate < 10) dateStr = dateStr + "0" + mCurDate; else dateStr = dateStr + mCurDate; return dateStr; } public String getYM() { String dateStr = mSelYear + "-"; if (mSelMonth + 1 < 10) dateStr = dateStr + "0" + (mSelMonth + 1) ; else dateStr = dateStr + (mSelMonth + 1); return dateStr; } /** * 初始化列宽和高 */ private void initSize() { // 初始化每列的大小 mColumnSize = getWidth() / NUM_COLUMNS; // 初始化每行的大小 mRowSize = getHeight() / NUM_ROWS; } /** * 设置可选择日期 * * @param dates 日期数据 */ public void setOptionalDate(List dates) { this.mOptionalDates = dates; invalidate(); } /** * 设置已选日期数据 */ public void setSelectedDates(List dates) { this.mSelectedDates = dates; } /** * 获取已选日期数据 */ public List getSelectedDates() { return mSelectedDates; } /** * 设置日历是否可以点击 */ @Override public void setClickable(boolean clickable) { this.mClickable = clickable; } /** * 设置年月日 * * @param year 年 * @param month 月 * @param date 日 */ private void setSelYTD(int year, int month, int date) { this.mSelYear = year; this.mSelMonth = month; this.mSelDate = date; } /** * 设置上一个月日历 */ public void setLastMonth() { int year = mSelYear; int month = mSelMonth; int day = mSelDate; // 如果是1月份,则变成12月份 if (month == 0) { year = mSelYear - 1; month = 11; } else if (getMonthDays(year, month) == day) { // 如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期 month = month - 1; day = getMonthDays(year, month); } else { month = month - 1; } setSelYTD(year, month, day); invalidate(); } /** * 设置下一个日历 */ public void setNextMonth() { int year = mSelYear; int month = mSelMonth; int day = mSelDate; // 如果是12月份,则变成1月份 if (month == 11) { year = mSelYear + 1; month = 0; } else if (getMonthDays(year, month) == day) { // 如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期 month = month + 1; day = getMonthDays(year, month); } else { month = month + 1; } setSelYTD(year, month, day); invalidate(); } /** * 获取当前展示的年和月份 * * @return 格式:2016年06月 */ public String getDate() { return mSelYear + "年" + (mSelMonth + 1) + "月"; } /** * 获取当前展示的日期 * * @return 格式:20160606 */ private String getSelData(int year, int month, int date) { String monty, day; month = (month + 1); // 判断月份是否有非0情况 if ((month) < 10) { monty = "0" + month; } else { monty = String.valueOf(month); } // 判断天数是否有非0情况 if ((date) < 10) { day = "0" + (date); } else { day = String.valueOf(date); } return year + monty + day; } private OnClickListener mListener; public interface OnClickListener { void onClickDateListener(String date); } /** * 设置点击回调 */ public void setOnClickDate(OnClickListener listener) { this.mListener = listener; } /** * 通过年份和月份 得到当月的日子 */ public static int getMonthDays(int year, int month) { month++; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 4: case 6: case 9: case 11: return 30; case 2: if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) { return 29; } else { return 28; } default: return -1; } } /** * 返回当前月份1号位于周几 * * @param year 年份 * @param month 月份,传入系统获取的,不需要正常的 * @return 日:1 一:2 二:3 三:4 四:5 五:6 六:7 */ public static int getFirstDayWeek(int year, int month) { Calendar calendar = Calendar.getInstance(); calendar.set(year, month, 1); return calendar.get(Calendar.DAY_OF_WEEK); } /** * 查询当前日期前(后)x天的日期 * * @param date 当前日期 * @param day 天数(如果day数为负数,说明是此日期前的天数) * @return yyyyMMdd */ private static String beforNumberDay(Date date, int day) { Calendar c = Calendar.getInstance(); c.setTime(date); c.add(Calendar.DAY_OF_YEAR, day); return new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } }