一、自定义日历界面
(1)自定义View日历星期
绘制两条直线,将View的宽度等分为七份,绘制星期
public class WeekDayView extends View {
private Paint paint;
private String[] weekString = new String[]{"S", "M", "T", "W", "T", "F", "S"};
private int lineColor = Color.parseColor("#CCE4F2");
private int lineWidth = 4;
private int weekColor = Color.parseColor("#1FC2F3");
private int weekSize = 34;
public WeekDayView(Context context) {
this(context, null);
}
public WeekDayView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WeekDayView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true); //设置抗锯齿的效果
paint.setStyle(Paint.Style.STROKE); //设置画笔的样式为描边
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
/**
* 测量宽度
*
* @param measureSpec
* @return
*/
private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 200;
if (specMode == MeasureSpec.AT_MOST) {//设置为wrap_content
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {//设置为match_parent或者为一个具体的值
result = specSize;
}
return result;
}
/**
* 测量高度
*
* @param measureSpec
* @return
*/
private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
//获取控件的宽高
int width = getWidth();
int height = getHeight();
//设置画笔的颜色
paint.setColor(lineColor);
//设置画笔的宽度
paint.setStrokeWidth(lineWidth);
//绘制上下两条线
canvas.drawLine(0, 0, width, 0, paint);
canvas.drawLine(0, height, width, height, paint);
int columnWidth = width / 7;
//绘制星期
paint.setStyle(Paint.Style.FILL);
paint.setColor(weekColor);
paint.setTextSize(weekSize);
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);
canvas.drawText(text, startX, startY, paint);
}
}
/**
* 设置线的颜色
*
* @param lineColor
*/
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
}
/**
* 设置线的宽度
*
* @param lineWidth
*/
public void setLineWidth(int lineWidth) {
this.lineWidth = lineWidth;
}
/**
* 设置字体的颜色
*
* @param weekColor
*/
public void setWeekColor(int weekColor) {
this.weekColor = weekColor;
}
/**
* 设置字体的大小
*
* @param weekSize
*/
public void setWeekSize(int weekSize) {
this.weekSize = weekSize;
}
}
(2)自定义日历日期
获取当前日期的天数,获取当前月的第一天是星期几,开始绘制将View设置为六行七列相同大小的空格,在空格中添加绘制日期。
public class MediaDayController extends View {
private Paint paint;
private int widthSize, heightSize;
private int daySize = 30;
private Calendar calendar;
private String day;
private int monthDay;
private int setYear, setMonth;
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context) {
this(context, null);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.N)
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(daySize);
calendar = Calendar.getInstance();
setYear = calendar.get(Calendar.YEAR);
setMonth = calendar.get(Calendar.MONTH) + 1;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
/**
* 测量宽度
*
* @param measureSpec
* @return
*/
private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {//设置为wrap_content
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {//设置为match_parent或者为一个具体的值
result = specSize;
}
return result;
}
/**
* 测量高度
*
* @param measureSpec
* @return
*/
private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
return result;
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取日期字体的宽高
widthSize = getWidth() / 7;
heightSize = getHeight() / 6;
//先指定年份和月份
calendar.set(Calendar.YEAR, setYear);
calendar.set(Calendar.MONTH, setMonth - 1);
//获取当前月的总天数
monthDay = calendar.getActualMaximum(Calendar.DATE);
//获取当前月的第一天是星期几
calendar.set(Calendar.DAY_OF_MONTH, 1);
int weekNumber = calendar.get(Calendar.DAY_OF_WEEK);
//循环绘制日期数字
for (int i = 0; i < monthDay; i++) {
day = (i + 1) + "";
//一行中的第几个
int column = (i + weekNumber - 1) % 7;
//第几行
int row = (i + weekNumber - 1) / 7;
int startX = (int) (widthSize * column + (widthSize - paint.measureText(day)) / 2);
int startY = (int) (heightSize * row + heightSize / 2 - (paint.ascent() + paint.descent()) / 2);
canvas.drawText(day, startX, startY, paint);
}
}
public void setSelect(int year, int month) {
setYear = year;
setMonth = month;
}
}
二、添加点击效果的日历界面
重新onTouchEvent方法,在方法中获取当前的点击坐标,计算当前坐标位置在第几行第几列,在onDraw判断是否存在,存在绘制背景。
public class MediaDayController extends View {
private Paint paint;
private int widthSize, heightSize;
private int daySize = 30;
private Calendar calendar;
private String day;
private int monthDay;
private int setYear, setMonth;
private int carryY;
private int columnX;
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context) {
this(context, null);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public MediaDayController(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.N)
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(daySize);
calendar = Calendar.getInstance();
setYear = calendar.get(Calendar.YEAR);
setMonth = calendar.get(Calendar.MONTH) + 1;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
/**
* 测量宽度
*
* @param measureSpec
* @return
*/
private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {//设置为wrap_content
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {//设置为match_parent或者为一个具体的值
result = specSize;
}
return result;
}
/**
* 测量高度
*
* @param measureSpec
* @return
*/
private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
return result;
}
private int carry;
private int column;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取日期字体的宽高
widthSize = getWidth() / 7;
heightSize = getHeight() / 6;
//先指定年份和月份
calendar.set(Calendar.YEAR, setYear);
calendar.set(Calendar.MONTH, setMonth - 1);
//获取当前月的总天数
monthDay = calendar.getActualMaximum(Calendar.DATE);
//获取当前月的第一天是星期几
calendar.set(Calendar.DAY_OF_MONTH, 1);
int weekNumber = calendar.get(Calendar.DAY_OF_WEEK);
//循环绘制日期数字
for (int i = 0; i < monthDay; i++) {
day = (i + 1) + "";
//第几行
carry = (i + weekNumber - 1) / 7;
//第几列
column = (i + weekNumber - 1) % 7;
//获取当前日期开始位置
int startX = (int) (widthSize * column + (widthSize - paint.measureText(day)) / 2);
int startY = (int) (heightSize * carry + heightSize / 2 - (paint.ascent() + paint.descent()) / 2);
//绘制背景圆
if (carry == carryY && column == columnX) {
int startRecX = widthSize * column;
int startRecY = heightSize * carry;
int endRecX = startRecX + widthSize;
int endRecY = startRecY + heightSize;
int px = DensityUtils.dip2px(getContext(), 12);
paint.setColor(Color.parseColor("#FFA500"));
canvas.drawCircle((startRecX + endRecX) / 2, (startRecY + endRecY) / 2, px, paint);
}
//绘制日期字体
paint.setColor(Color.BLACK);
canvas.drawText(day, startX, startY, paint);
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//获取点击位置
float x = event.getX();
float y = event.getY();
//计算点击位置在第几行第几列
carryY = (int) (y / heightSize);
columnX = (int) (x / widthSize);
//刷新界面
invalidate();
return true;
}
return super.onTouchEvent(event);
}
/**
* 设置日期
*
* @param year
* @param month
*/
public void setSelect(int year, int month) {
setYear = year;
setMonth = month;
}
}