自定义日历
- 日期的绘制
- 日期点击事件
- 日期的事件提醒
- 日期的颜色设置
1. 日历的绘制
这是参考的网上的部分自定义日历加上自己的修改
public class MonthDateView extends View {
private static final int NUM_COLUMNS = 7;
private static final int NUM_ROWS = 6;
private final int touchSlop;
private Paint mPaint;
private int mDayColor = Color.parseColor("#000000");
private int mSelectDayColor = Color.parseColor("#ffffff");
private int mSelectBGColor = Color.parseColor("#1FC2F3");
private int mCurrentColor = Color.parseColor("#ff0000");
private int mCurrYear, mCurrMonth, mCurrDay;
private int mSelYear, mSelMonth, mSelDay;
private int mColumnSize, mRowSize;
private DisplayMetrics mDisplayMetrics;
private int mDaySize = 18;
private TextView tv_date, tv_week;
private int weekRow;
private int[][] daysString;
private int mCircleRadius = 4;
private DateClick dateClick;
private int mCircleColor = Color.parseColor("#ff0000");
private List<Integer> daysHasThingList;
private List<Integer> grayDayList;
private boolean grayDay = false;
public MonthDateView(Context context, AttributeSet attrs) {
super(context, attrs);
mDisplayMetrics = getResources().getDisplayMetrics();
Calendar calendar = Calendar.getInstance();
mPaint = new Paint();
mCurrYear = calendar.get(Calendar.YEAR);
//这地方+1是由于系统默认的月份是0-11月 和传统的1-12月有误差
mCurrMonth = calendar.get(Calendar.MONTH)+1;
mCurrDay = calendar.get(Calendar.DATE);
setSelectYearMonth(mCurrYear, mCurrMonth, mCurrDay);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = mDisplayMetrics.densityDpi * 200;
}
// if(widthMode == MeasureSpec.AT_MOST){
// widthSize = mDisplayMetrics.densityDpi * 300;
// }
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
initSize();
daysString = new int[6][7];
mPaint.setTextSize(mDaySize * mDisplayMetrics.scaledDensity);
String dayString;
int mMonthDays = DateHelper.getMonthDays(mSelYear, mSelMonth);
int weekNumber = DateHelper.getFirstDayWeek(mSelYear, mSelMonth);
Log.d("DateView", "DateView:" + mSelMonth + "月1号周" + weekNumber);
for (int day = 0; day < mMonthDays; day++) {
dayString = (day + 1) + "";
int column = (day + weekNumber - 1) % 7;
int row = (day + weekNumber - 1) / 7;
daysString[row][column] = day + 1;
int startX = (int) (mColumnSize * column + (mColumnSize - mPaint.measureText(dayString)) / 2);
int startY = (int) (mRowSize * row + mRowSize / 2 - (mPaint.ascent() + mPaint.descent()) / 2);
// 这个地方可以对背景色进行设置,形状和颜色可以按照自己定义的来
// if(dayString.equals(mSelDay+"")){
// //绘制背景色矩形
// int startRecX = mColumnSize * column;
// int startRecY = mRowSize * row;
// int endRecX = startRecX + mColumnSize;
// int endRecY = startRecY + mRowSize;
// mPaint.setColor(mSelectBGColor);
// canvas.drawRect(startRecX, startRecY, endRecX, endRecY, mPaint);
// //记录第几行,即第几周
// weekRow = row + 1;
// }
//绘制事务圆形标志 我这边是由于公司要点击背景色发生变化,所以设置为背
//景色为空,通过事务来描绘背景的黄色圆圈
drawCircle(row, column, day + 1, canvas);
//下面是对日期天数的绘制,可以针对自己的需求自定义修改
if (dayString.equals(mSelDay + "")) {
mPaint.setColor(mSelectDayColor);
} else if (dayString.equals(mCurrDay + "") && mCurrDay != mSelDay && mCurrMonth == mSelMonth) {
//当天
mPaint.setColor(mDayColor);
}else {
mPaint.setColor(mDayColor);
}
canvas.drawText(dayString, startX, startY, mPaint);
if (tv_date != null) {
tv_date.setText(mSelYear + "年" + mSelMonth + "月");
}
if (tv_week != null) {
tv_week.setText("第" + weekRow + "周");
}
}
}
//绘制事务标志
private void drawCircle(int row, int column, int day, Canvas canvas) {
if (daysHasThingList != null && daysHasThingList.size() > 0) {
if (!daysHasThingList.contains(day)) {
//设置事务标志颜色 mPaint.setColor(Color.parseColor("#ffffff"));
float circleX = (float) (mColumnSize * column + mColumnSize * 0.5);
float circley = (float) (mRowSize * row + mRowSize * 0.5);
canvas.drawCircle(circleX, circley, mCircleRadius, mPaint);
return;
}
mPaint.setColor(mCircleColor);
int startRecX = mColumnSize * column;
int endRecX = startRecX + mColumnSize;
//事务圆的半径
mCircleRadius = (Math.abs(endRecX - startRecX)) * 2 / 7;
//圆心坐标
float circleX = (float) (mColumnSize * column + mColumnSize * 0.5);
float circley = (float) (mRowSize * row + mRowSize * 0.5);
canvas.drawCircle(circleX, circley, mCircleRadius, mPaint);
}
}
@Override
public boolean performClick() {
return super.performClick();
}
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:
int upX = (int) event.getX();
int upY = (int) event.getY();
if (Math.abs(upX - downX) < touchSlop && Math.abs(upY - downY) < touchSlop) {//点击事件
performClick();
doClickAction((upX + downX) / 2, (upY + downY) / 2);
}
break;
}
return true;
}
/**
* 初始化列宽行高
*/
private void initSize() {
mColumnSize = getWidth() / NUM_COLUMNS;
mRowSize = getHeight() / NUM_ROWS;
}
/**
* 设置年月
*
* @param year
* @param month
*/
private void setSelectYearMonth(int year, int month, int day) {
mSelYear = year;
mSelMonth = month;
mSelDay = day;
}
/**
* 执行点击事件
*
* @param x
* @param y
*/
private void doClickAction(int x, int y) {
int row = y / mRowSize;
int column = x / mColumnSize;
int mMonthDays = DateHelper.getMonthDays(mSelYear, mSelMonth);
setSelectYearMonth(mSelYear, mSelMonth, daysString[row][column]);
invalidate();
//执行activity发送过来的点击处理事件
if (dateClick != null) {
dateClick.onClickOnDate();
}
}
/**
* 左点击,日历向后翻页
*/
public void onLeftClick() {
int year = mSelYear;
int month = mSelMonth;
int day = mSelDay;
if (month == 1) {//若果是1月份,则变成12月份
year = mSelYear - 1;
month = 12;
} else if (DateHelper.getMonthDays(year, month) == day) {
//如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
month = month - 1;
day = DateHelper.getMonthDays(year, month);
} else {
month = month - 1;
}
setSelectYearMonth(year, month, day);
invalidate();
}
/**
* 右点击,日历向前翻页
*/
public void onRightClick() {
int year = mSelYear;
int month = mSelMonth;
int day = mSelDay;
if (month == 12) {//若果是12月份,则变成1月份
year = mSelYear + 1;
month = 1;
} else if (DateHelper.getMonthDays(year, month) == day) {
//如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
month = month + 1;
day = DateHelper.getMonthDays(year, month);
} else {
month = month + 1;
}
setSelectYearMonth(year, month, day);
invalidate();
}
/**
* 获取选择的年份
*
* @return
*/
public int getmSelYear() {
return mSelYear;
}
/**
* 获取选择的月份
*
* @return
*/
public int getmSelMonth() {
return mSelMonth;
}
/**
* 获取选择的日期
*/
public int getmSelDay() {
return this.mSelDay;
}
/**
* 普通日期的字体颜色,默认黑色
*
* @param mDayColor
*/
public void setmDayColor(int mDayColor) {
this.mDayColor = mDayColor;
}
/**
* 选择日期的颜色,默认为白色
*
* @param mSelectDayColor
*/
public void setmSelectDayColor(int mSelectDayColor) {
this.mSelectDayColor = mSelectDayColor;
}
/**
* 选中日期的背景颜色,默认蓝色
*
* @param mSelectBGColor
*/
public void setmSelectBGColor(int mSelectBGColor) {
this.mSelectBGColor = mSelectBGColor;
}
/**
* 当前日期不是选中的颜色,默认红色
*
* @param mCurrentColor
*/
public void setmCurrentColor(int mCurrentColor) {
this.mCurrentColor = mCurrentColor;
}
/**
* 日期的大小,默认18sp
*
* @param mDaySize
*/
public void setmDaySize(int mDaySize) {
this.mDaySize = mDaySize;
}
/**
* 设置显示当前日期的控件
*
* @param tv_date 显示日期
*/
public void setTextView(TextView tv_date) {
this.tv_date = tv_date;
invalidate();
}
/**
* 设置事务天数
*
* @param daysHasThingList
*/
public void setDaysHasThingList(List<Integer> daysHasThingList) {
this.daysHasThingList = daysHasThingList;
}
/**
* 设置事务天数
*
* @param grayDayList
*/
public void setGrayDayList(List<Integer> grayDayList) {
this.grayDayList = grayDayList;
grayDay = true;
}
/***
* 设置圆圈的半径,默认为6
*
* @param mCircleRadius
*/
public void setmCircleRadius(int mCircleRadius) {
this.mCircleRadius = mCircleRadius;
}
/**
* 设置圆圈的半径
*
* @param mCircleColor
*/
public void setmCircleColor(int mCircleColor) {
this.mCircleColor = mCircleColor;
}
/**
* 设置日期的点击回调事件
*
* @author shiwei.deng
*/
public interface DateClick {
public void onClickOnDate();
}
/**
* 设置日期点击事件
*
* @param dateClick
*/
public void setDateClick(DateClick dateClick) {
this.dateClick = dateClick;
}
/**
* 跳转至今天
*/
public void setTodayToView() {
setSelectYearMonth(mCurrYear, mCurrMonth, mCurrDay);
invalidate();
}
绘制周一 -周日
public class WeekDayView extends View {
//周一到周五的颜色
private int mWeedayColor = Color.parseColor("#000000");
//周六、周日的颜色
private int mWeekendColor = Color.parseColor("#000000");
private int mWeekSize = 12;
private Paint paint;
private DisplayMetrics mDisplayMetrics;
private String[] weekString = new String[]{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
public WeekDayView(Context context, AttributeSet attrs) {
super(context, attrs);
mDisplayMetrics = getResources().getDisplayMetrics();
paint = new Paint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if(heightMode == MeasureSpec.AT_MOST){
heightSize = mDisplayMetrics.densityDpi * 30;
}
// if(widthMode == MeasureSpec.AT_MOST){
// widthSize = mDisplayMetrics.densityDpi * 300;
// }
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(mWeekSize * mDisplayMetrics.scaledDensity);
int columnWidth = width / 7;
for(int i=0;i < weekString.length;i++){
String text = weekString[i];
int fontWidth = (int) paint.measureText(text);
int startX = columnWidth * i + (columnWidth - fontWidth)/2;
int startY = (int) (height/2 - (paint.ascent() + paint.descent())/2);
if(text.indexOf("日") > -1|| text.indexOf("六") > -1){
paint.setColor(mWeekendColor);
}else{
paint.setColor(mWeedayColor);
}
canvas.drawText(text, startX, startY, paint);
}
}
/**
* 设置周一-五的颜色
* @return
*/
public void setmWeedayColor(int mWeedayColor) {
this.mWeedayColor = mWeedayColor;
}
/**
* 设置周六、周日的颜色
* @param mWeekendColor
*/
public void setmWeekendColor(int mWeekendColor) {
this.mWeekendColor = mWeekendColor;
}
/**
* 设置字体的大小
* @param mWeekSize
*/
public void setmWeekSize(int mWeekSize) {
this.mWeekSize = mWeekSize;
}
/**
* 设置星期的形式
* @param weekString
* 默认值 "日","一","二","三","四","五","六"
*/
public void setWeekString(String[] weekString) {
this.weekString = weekString;
}
}
日期帮助类
public class DateHelper {
/**
* 默认的日期样式:yyyy-MM-dd
*/
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DATE_TIME_FORMAT_SHORT="yyyy-M-d H:m";
public static final String DATE_TIME_FORMAT_BIG_SHORT="yyyy-MM-dd HH:mm";
public static final String DATE_TIME_FORMAT="yyyy-MM-dd HH:mm:ss";
public static final int YEAR = 1;
public static final int MONTH = 2;
public static final int DAY = 3;
public static final int HOUR = 4;
public static final int MINUTE = 5;
public static final int SECOND = 6;
public static final int MILLISECOND = 7;
public DateHelper(){
}
public static int getMonthDays(int year, int month) {
if (month > 12) {
month = 1;
year += 1;
} else if (month < 1) {
month = 12;
year -= 1;
}
int[] arr = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int days = 0;
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
arr[1] = 29; // 闰年2月29天
}
try {
days = arr[month - 1];
} catch (Exception e) {
e.getStackTrace();
}
return days;
}
public static int getYear() {
return Calendar.getInstance().get(Calendar.YEAR);
}
public static int getMonth() {
return Calendar.getInstance().get(Calendar.MONTH) + 1;
}
public static int getCurrentMonthDay() {
return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
}
public static int getWeekDay() {
return Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
}
/**
* 返回当前月份1号位于周几
* @param year
* 年份
* @param month
* 这个地方是我在绘制日历时候传入的正常的月份
* 需要做一个减1处理,这又有个地方是周日为第一天和周一为第一天是不一样的,需要自己做处理
* @return
* 日:1 一:2 二:3 三:4 四:5 五:6 六:7
*/
public static int getFirstDayWeek(int year, int month){
Calendar calendar = Calendar.getInstance();
int firstDayOfWeek = calendar.getFirstDayOfWeek();
Log.e("firstDayOfWeek",firstDayOfWeek+"");
calendar.set(year, month-1, 1);
int i1 = calendar.get(Calendar.DATE);
int i = calendar.get(Calendar.DAY_OF_WEEK);
return i;
}
}
日期layout
<LinearLayout 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:layout_centerInParent="true"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.quwanbei.haihuilai.caledertest.MainActivity">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:gravity="center_vertical"
android:paddingTop="3dp">
<LinearLayout
android:id="@+id/date_operator_ll"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:layout_gravity="center_vertical"
android:gravity="center"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/iv_left"
android:padding="8dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/last"
android:contentDescription="@null" />
</RelativeLayout>
<TextView
android:id="@+id/date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:gravity="center_horizontal"
android:text=""
android:textColor="#1d1d1d"
android:textSize="18sp" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/iv_right"
android:padding="8dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/next"
android:contentDescription="@null" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#f3f3f3" />
<com.quwanbei.haihuilai.caledertest.WeekDayView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="14dp" />
<com.quwanbei.haihuilai.caledertest.MonthDateView
android:id="@+id/monthDateView"
android:layout_width="fill_parent"
android:layout_height="200dp" />
</LinearLayout>
</LinearLayout>
Activity设置
public class MainActivity extends AppCompatActivity {
private RelativeLayout iv_left;
private RelativeLayout iv_right;
private MonthDateView monthDateView;
private TextView tv_date;
private ArrayList<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new ArrayList<>();
list.add(10+"");
list.add(12+"");
list.add(15+"");
list.add(16+"");
iv_left = (RelativeLayout) findViewById(R.id.iv_left);
iv_right = (RelativeLayout) findViewById(R.id.iv_right);
monthDateView = (MonthDateView) findViewById(R.id.monthDateView);
tv_date = (TextView) findViewById(R.id.date_text);
monthDateView.setTextView(tv_date);
monthDateView.setDaysHasThingList(list);
monthDateView.setmCircleRadius(60);
monthDateView.setmCircleColor(Color.parseColor("#ffda8c"));
monthDateView.setmSelectDayColor(Color.parseColor("#00beab"));
monthDateView.setmCurrentColor(Color.parseColor("#000000"));
monthDateView.setmDaySize(14);
monthDateView.setDateClick(new MonthDateView.DateClick() {
@Override
public void onClickOnDate() {
if(!list.contains(monthDateView.getmSelDay()+"")) {
list.add(monthDateView.getmSelDay()+"");
Toast.makeText(getApplication(), "点击了:" + monthDateView.getmSelDay(), Toast.LENGTH_SHORT).show();
}else{
list.remove(monthDateView.getmSelDay()+"");
}
}
});
setOnlistener();
}
private void setOnlistener(){
iv_left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
monthDateView.onLeftClick();
}
});
iv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
monthDateView.onRightClick();
}
});
}
}
需要标注的地方都写有注释,有不明白的地方留言问我
刚开始写,技术不太好,多多指教。