package com.kuanzhai.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:
|
* <p>
|
* 自定义日历View,可多选
|
*
|
* <com.hxyy.assistant.views.CalendarView
|
* android:id="@+id/calendarView"
|
* android:layout_width="match_parent"
|
* android:layout_height="260dp"
|
* android:layout_marginStart="20dp"
|
* android:layout_marginEnd="20dp"
|
* app:layout_constraintTop_toBottomOf="@id/weekView" />
|
*/
|
public class CalendarView extends View {
|
|
// 列的数量
|
private static final int NUM_COLUMNS = 7;
|
// 行的数量
|
private static final int NUM_ROWS = 6;
|
|
/**
|
* 可选日期数据
|
*/
|
private List<String> mOptionalDates = new ArrayList<>();
|
|
private int nowDay = 0;
|
|
/**
|
* 以选日期数据
|
*/
|
private List<String> mSelectedDates = new ArrayList<>();
|
|
/**
|
* 异常日期数据
|
*/
|
private List<String> 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<NUM_ROWS;i++){
|
// canvas.drawLine(0,i*mRowSize,getWidth(),i*mRowSize,mPaint);
|
// }
|
|
|
String dayStr;
|
// 获取当月一共有多少天
|
mMonthDays = getMonthDays(mSelYear, mSelMonth);
|
// 获取当月第一天位于周几
|
mWeekNumber = getFirstDayWeek(mSelYear, mSelMonth);
|
|
for (int day = 0; day < mMonthDays; day++) {
|
dayStr = String.valueOf(day + 1);
|
int column = (day + mWeekNumber - 1) % 7;
|
int row = (day + mWeekNumber - 1) / 7;
|
mDays[row][column] = day + 1;
|
int startX = (int) (mColumnSize * column + (mColumnSize - mPaint.measureText(dayStr)) / 2);
|
int startY = (int) (mRowSize * row + mRowSize / 2 - (mPaint.ascent() + mPaint.descent()) / 2);
|
|
// 判断当前天数是否可选
|
if (Integer.parseInt(getSelData(mSelYear, mSelMonth, mDays[row][column])) >= 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<String> 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<String> dates) {
|
this.mOptionalDates = dates;
|
invalidate();
|
}
|
|
/**
|
* 设置已选日期数据
|
*/
|
public void setSelectedDates(List<String> dates) {
|
this.mSelectedDates = dates;
|
}
|
|
/**
|
* 获取已选日期数据
|
*/
|
public List<String> 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());
|
}
|
}
|