package com.example.zbytexttwo;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MainJmActivity extends AppCompatActivity {
private CustomCalendar cal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_jm);
cal = (CustomCalendar)findViewById(R.id.cal);
//TODO 模拟请求当月数据
final List<DayFinish> list = new ArrayList<>();
list.add(new DayFinish(1,2,2));
list.add(new DayFinish(2,1,2));
list.add(new DayFinish(3,0,2));
list.add(new DayFinish(4,2,2));
list.add(new DayFinish(5,2,2));
list.add(new DayFinish(6,2,2));
list.add(new DayFinish(7,2,2));
list.add(new DayFinish(8,0,2));
list.add(new DayFinish(9,1,2));
list.add(new DayFinish(10,2,2));
list.add(new DayFinish(11,5,2));
list.add(new DayFinish(12,2,2));
list.add(new DayFinish(13,2,2));
list.add(new DayFinish(14,3,2));
list.add(new DayFinish(15,2,2));
list.add(new DayFinish(16,1,2));
list.add(new DayFinish(17,0,2));
list.add(new DayFinish(18,2,2));
list.add(new DayFinish(19,2,2));
list.add(new DayFinish(20,0,2));
list.add(new DayFinish(21,2,2));
list.add(new DayFinish(22,1,2));
list.add(new DayFinish(23,2,0));
list.add(new DayFinish(24,0,2));
list.add(new DayFinish(25,2,2));
list.add(new DayFinish(26,2,2));
list.add(new DayFinish(27,2,2));
list.add(new DayFinish(28,2,2));
list.add(new DayFinish(29,2,2));
list.add(new DayFinish(30,2,2));
list.add(new DayFinish(31,2,2));
cal.setRenwu("2017年1月", list);
cal.setOnClickListener(new CustomCalendar.onClickListener() {
@Override
public void onLeftRowClick() {
Toast.makeText(MainJmActivity.this, "点击减箭头", Toast.LENGTH_SHORT).show();
cal.monthChange(-1);
new Thread(){
@Override
public void run() {
try{
Thread.sleep(1000);
MainJmActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
cal.setRenwu(list);
}
});
}catch (Exception e){
}
}
}.start();
}
@Override
public void onRightRowClick() {
Toast.makeText(MainJmActivity.this, "点击加箭头", Toast.LENGTH_SHORT).show();
cal.monthChange(1);
new Thread(){
@Override
public void run() {
try{
Thread.sleep(1000);
MainJmActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
cal.setRenwu(list);
}
});
}catch (Exception e){
}
}
}.start();
}
@Override
public void onTitleClick(String monthStr, Date month) {
Toast.makeText(MainJmActivity.this, "点击了标题:"+monthStr, Toast.LENGTH_SHORT).show();
}
@Override
public void onWeekClick(int weekIndex, String weekStr) {
Toast.makeText(MainJmActivity.this, "点击了星期:"+weekStr, Toast.LENGTH_SHORT).show();
}
@Override
public void onDayClick(int day, String dayStr, DayFinish finish) {
Toast.makeText(MainJmActivity.this, "点击了日期:"+dayStr, Toast.LENGTH_SHORT).show();
Log.w("", "点击了日期:"+dayStr);
}
});
}
class DayFinish{
int day;
int all;
int finish;
public DayFinish(int day, int finish, int all) {
this.day = day;
this.all = all;
this.finish = finish;
}
}
}
MainJmActivity
package com.example.zbytexttwo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* author : openXu
* create at : 2017/1/3 9:56
* blog : http://blog.csdn.net/xmxkf
* gitHub : https://github.com/openXu
* project : CustomCalendar
* class name : CustomCalendar
* version : 1.0
* class describe:自定义日历控件
*/
public class CustomCalendar extends View{
private String TAG = "CustomCalendar";
/** 各部分背景*/
private int mBgMonth, mBgWeek, mBgDay, mBgPre;
/** 标题的颜色、大小*/
private int mTextColorMonth;
private float mTextSizeMonth;
private int mMonthRowL, mMonthRowR;
private float mMonthRowSpac;
private float mMonthSpac;
/** 星期的颜色、大小*/
private int mTextColorWeek, mSelectWeekTextColor;
private float mTextSizeWeek;
/** 日期文本的颜色、大小*/
private int mTextColorDay;
private float mTextSizeDay;
/** 任务次数文本的颜色、大小*/
private int mTextColorPreFinish, mTextColorPreUnFinish, mTextColorPreNull;
private float mTextSizePre;
/** 选中的文本的颜色*/
private int mSelectTextColor;
/** 选中背景*/
private int mSelectBg, mCurrentBg;
private float mSelectRadius, mCurrentBgStrokeWidth;
private float[] mCurrentBgDashPath;
/** 行间距*/
private float mLineSpac;
/** 字体上下间距*/
private float mTextSpac;
private Paint mPaint;
private Paint bgPaint;
private float titleHeight, weekHeight, dayHeight, preHeight, oneHeight;
private int columnWidth; //每列宽度
private Date month; //当前的月份
private boolean isCurrentMonth; //展示的月份是否是当前月
private int currentDay, selectDay, lastSelectDay; //当前日期 、 选中的日期 、上一次选中的日期(避免造成重复回调请求)
private int dayOfMonth; //月份天数
private int firstIndex; //当月第一天位置索引
private int todayWeekIndex;//今天是星期几
private int firstLineNum, lastLineNum; //第一行、最后一行能展示多少日期
private int lineNum; //日期行数
private String[] WEEK_STR = new String[]{"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat", };
public CustomCalendar(Context context) {
this(context, null);
}
public CustomCalendar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性的值
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCalendar, defStyleAttr, 0);
mBgMonth = a.getColor(R.styleable.CustomCalendar_mBgMonth, Color.TRANSPARENT);
mBgWeek = a.getColor(R.styleable.CustomCalendar_mBgWeek, Color.TRANSPARENT);
mBgDay = a.getColor(R.styleable.CustomCalendar_mBgDay, Color.TRANSPARENT);
mBgPre = a.getColor(R.styleable.CustomCalendar_mBgPre, Color.TRANSPARENT);
mMonthRowL = a.getResourceId(R.styleable.CustomCalendar_mMonthRowL, R.drawable.custom_calendar_row_left);
mMonthRowR = a.getResourceId(R.styleable.CustomCalendar_mMonthRowR, R.drawable.custom_calendar_row_right);
mMonthRowSpac = a.getDimension(R.styleable.CustomCalendar_mMonthRowSpac, 20);
mTextColorMonth = a.getColor(R.styleable.CustomCalendar_mTextColorMonth, Color.BLACK);
mTextSizeMonth = a.getDimension(R.styleable.CustomCalendar_mTextSizeMonth, 100);
mMonthSpac = a.getDimension(R.styleable.CustomCalendar_mMonthSpac, 20);
mTextColorWeek = a.getColor(R.styleable.CustomCalendar_mTextColorWeek, Color.BLACK);
mSelectWeekTextColor = a.getColor(R.styleable.CustomCalendar_mSelectWeekTextColor, Color.BLACK);
mTextSizeWeek = a.getDimension(R.styleable.CustomCalendar_mTextSizeWeek, 70);
mTextColorDay = a.getColor(R.styleable.CustomCalendar_mTextColorDay, Color.GRAY);
mTextSizeDay = a.getDimension(R.styleable.CustomCalendar_mTextSizeDay, 70);
mTextColorPreFinish = a.getColor(R.styleable.CustomCalendar_mTextColorPreFinish, Color.BLUE);
mTextColorPreUnFinish = a.getColor(R.styleable.CustomCalendar_mTextColorPreUnFinish, Color.BLUE);
mTextColorPreNull = a.getColor(R.styleable.CustomCalendar_mTextColorPreNull, Color.BLUE);
mTextSizePre = a.getDimension(R.styleable.CustomCalendar_mTextSizePre, 40);
mSelectTextColor = a.getColor(R.styleable.CustomCalendar_mSelectTextColor, Color.YELLOW);
mCurrentBg = a.getColor(R.styleable.CustomCalendar_mCurrentBg, Color.GRAY);
try {
int dashPathId = a.getResourceId(R.styleable.CustomCalendar_mCurrentBgDashPath, R.array.customCalendar_currentDay_bg_DashPath);
int[] array = getResources().getIntArray(dashPathId);
mCurrentBgDashPath = new float[array.length];
for(int i=0;i<array.length;i++){
mCurrentBgDashPath[i]=array[i];
}
}catch (Exception e){
e.printStackTrace();
mCurrentBgDashPath = new float[]{2, 3, 2, 3};
}
mSelectBg = a.getColor(R.styleable.CustomCalendar_mSelectBg, Color.YELLOW);
mSelectRadius = a.getDimension(R.styleable.CustomCalendar_mSelectRadius, 20);
mCurrentBgStrokeWidth = a.getDimension(R.styleable.CustomCalendar_mCurrentBgStrokeWidth, 5);
mLineSpac = a.getDimension(R.styleable.CustomCalendar_mLineSpac, 20);
mTextSpac = a.getDimension(R.styleable.CustomCalendar_mTextSpac, 20);
a.recycle(); //注意回收
initCompute();
}
/**计算相关常量,构造方法中调用*/
private void initCompute(){
mPaint = new Paint();
bgPaint = new Paint();
mPaint.setAntiAlias(true); //抗锯齿
bgPaint.setAntiAlias(true); //抗锯齿
map = new HashMap<>();
//标题高度
mPaint.setTextSize(mTextSizeMonth);
titleHeight = FontUtil.getFontHeight(mPaint) + 2 * mMonthSpac;
//星期高度
mPaint.setTextSize(mTextSizeWeek);
weekHeight = FontUtil.getFontHeight(mPaint);
//日期高度
mPaint.setTextSize(mTextSizeDay);
dayHeight = FontUtil.getFontHeight(mPaint);
//次数字体高度
mPaint.setTextSize(mTextSizePre);
preHeight = FontUtil.getFontHeight(mPaint);
//每行高度 = 行间距 + 日期字体高度 + 字间距 + 次数字体高度
oneHeight = mLineSpac + dayHeight + mTextSpac + preHeight;
//默认当前月份
String cDateStr = getMonthStr(new Date());
// cDateStr = "2015年08月";
setMonth(cDateStr);
}
/**设置月份*/
private void setMonth(String Month){
//设置的月份(2017年01月)
month = str2Date(Month);
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
//获取今天是多少号
currentDay = calendar.get(Calendar.DAY_OF_MONTH);
todayWeekIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
Date cM = str2Date(getMonthStr(new Date()));
//判断是否为当月
if(cM.getTime() == month.getTime()){
isCurrentMonth = true;
selectDay = currentDay;//当月默认选中当前日
}else{
isCurrentMonth = false;
selectDay = 0;
}
Log.d(TAG, "设置月份:"+month+" 今天"+currentDay+"号, 是否为当前月:"+isCurrentMonth);
calendar.setTime(month);
dayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
//第一行1号显示在什么位置(星期几)
firstIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
lineNum = 1;
//第一行能展示的天数
firstLineNum = 7-firstIndex;
lastLineNum = 0;
int shengyu = dayOfMonth - firstLineNum;
while (shengyu>7){
lineNum ++;
shengyu-=7;
}
if(shengyu>0){
lineNum ++;
lastLineNum = shengyu;
}
Log.i(TAG, getMonthStr(month)+"一共有"+dayOfMonth+"天,第一天的索引是:"+firstIndex+" 有"+lineNum+
"行,第一行"+firstLineNum+"个,最后一行"+lastLineNum+"个");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//宽度 = 填充父窗体
int widthSize = MeasureSpec.getSize(widthMeasureSpec); //获取宽的尺寸
columnWidth = widthSize / 7;
//高度 = 标题高度 + 星期高度 + 日期行数*每行高度
float height = titleHeight + weekHeight + (lineNum * oneHeight);
Log.v(TAG, "标题高度:"+titleHeight+" 星期高度:"+weekHeight+" 每行高度:"+oneHeight+
" 行数:"+ lineNum + " \n控件高度:"+height);
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
(int)height);
}
@Override
protected void onDraw(Canvas canvas) {
drawMonth(canvas);
drawWeek(canvas);
drawDayAndPre(canvas);
}
/**绘制月份*/
private int rowLStart, rowRStart, rowWidth;
private void drawMonth(Canvas canvas){
//背景
bgPaint.setColor(mBgMonth);
RectF rect = new RectF(0, 0, getWidth(), titleHeight);
canvas.drawRect(rect, bgPaint);
//绘制月份
mPaint.setTextSize(mTextSizeMonth);
mPaint.setColor(mTextColorMonth);
float textLen = FontUtil.getFontlength(mPaint, getMonthStr(month));
float textStart = (getWidth() - textLen)/ 2;
canvas.drawText(getMonthStr(month), textStart,
mMonthSpac+FontUtil.getFontLeading(mPaint), mPaint);
/*绘制左右箭头*/
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), mMonthRowL);
int h = bitmap.getHeight();
rowWidth = bitmap.getWidth();
//float left, float top
rowLStart = (int)(textStart-2*mMonthRowSpac-rowWidth);
canvas.drawBitmap(bitmap, rowLStart+mMonthRowSpac , (titleHeight - h)/2, new Paint());
bitmap = BitmapFactory.decodeResource(getResources(), mMonthRowR);
rowRStart = (int)(textStart+textLen);
canvas.drawBitmap(bitmap, rowRStart+mMonthRowSpac, (titleHeight - h)/2, new Paint());
}
/**绘制绘制星期*/
private void drawWeek(Canvas canvas){
//背景
bgPaint.setColor(mBgWeek);
RectF rect = new RectF(0, titleHeight, getWidth(), titleHeight + weekHeight);
canvas.drawRect(rect, bgPaint);
//绘制星期:七天
mPaint.setTextSize(mTextSizeWeek);
for(int i = 0; i < WEEK_STR.length; i++){
if(todayWeekIndex == i && isCurrentMonth){
mPaint.setColor(mSelectWeekTextColor);
}else{
mPaint.setColor(mTextColorWeek);
}
int len = (int)FontUtil.getFontlength(mPaint, WEEK_STR[i]);
int x = i * columnWidth + (columnWidth - len)/2;
canvas.drawText(WEEK_STR[i], x, titleHeight + FontUtil.getFontLeading(mPaint), mPaint);
}
}
/**绘制日期和次数*/
private void drawDayAndPre(Canvas canvas){
//某行开始绘制的Y坐标,第一行开始的坐标为标题高度+星期部分高度
float top = titleHeight+weekHeight;
//行
for(int line = 0; line < lineNum; line++){
if(line == 0){
//第一行
drawDayAndPre(canvas, top, firstLineNum, 0, firstIndex);
}else if(line == lineNum-1){
//最后一行
top += oneHeight;
drawDayAndPre(canvas, top, lastLineNum, firstLineNum+(line-1)*7, 0);
}else{
//满行
top += oneHeight;
drawDayAndPre(canvas, top, 7, firstLineNum+(line-1)*7, 0);
}
}
}
/**
* 绘制某一行的日期
* @param canvas
* @param top 顶部坐标
* @param count 此行需要绘制的日期数量(不一定都是7天)
* @param overDay 已经绘制过的日期,从overDay+1开始绘制
* @param startIndex 此行第一个日期的星期索引
*/
private void drawDayAndPre(Canvas canvas, float top,
int count, int overDay, int startIndex){
// Log.e(TAG, "总共"+dayOfMonth+"天 有"+lineNum+"行"+ " 已经画了"+overDay+"天,下面绘制:"+count+"天");
//背景
float topPre = top + mLineSpac + dayHeight;
bgPaint.setColor(mBgDay);
RectF rect = new RectF(0, top, getWidth(), topPre);
canvas.drawRect(rect, bgPaint);
bgPaint.setColor(mBgPre);
rect = new RectF(0, topPre, getWidth(), topPre + mTextSpac + dayHeight);
canvas.drawRect(rect, bgPaint);
mPaint.setTextSize(mTextSizeDay);
float dayTextLeading = FontUtil.getFontLeading(mPaint);
mPaint.setTextSize(mTextSizePre);
float preTextLeading = FontUtil.getFontLeading(mPaint);
// Log.v(TAG, "当前日期:"+currentDay+" 选择日期:"+selectDay+" 是否为当前月:"+isCurrentMonth);
for(int i = 0; i<count; i++){
int left = (startIndex + i)*columnWidth;
int day = (overDay+i+1);
mPaint.setTextSize(mTextSizeDay);
//如果是当前月,当天日期需要做处理
if(isCurrentMonth && currentDay == day){
mPaint.setColor(mTextColorDay);
bgPaint.setColor(mCurrentBg);
bgPaint.setStyle(Paint.Style.STROKE); //空心
PathEffect effect = new DashPathEffect(mCurrentBgDashPath, 1);
bgPaint.setPathEffect(effect); //设置画笔曲线间隔
bgPaint.setStrokeWidth(mCurrentBgStrokeWidth); //画笔宽度
//绘制空心圆背景
canvas.drawCircle(left+columnWidth/2, top + mLineSpac +dayHeight/2,
mSelectRadius-mCurrentBgStrokeWidth, bgPaint);
}
//绘制完后将画笔还原,避免脏笔
bgPaint.setPathEffect(null);
bgPaint.setStrokeWidth(0);
bgPaint.setStyle(Paint.Style.FILL);
//选中的日期,如果是本月,选中日期正好是当天日期,下面的背景会覆盖上面绘制的虚线背景
if(selectDay == day){
//选中的日期字体白色,橙色背景
mPaint.setColor(mSelectTextColor);
bgPaint.setColor(mSelectBg);
//绘制橙色圆背景,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;
canvas.drawCircle(left+columnWidth/2, top + mLineSpac +dayHeight/2, mSelectRadius, bgPaint);
}else{
mPaint.setColor(mTextColorDay);
}
int len = (int)FontUtil.getFontlength(mPaint, day+"");
int x = left + (columnWidth - len)/2;
canvas.drawText(day+"", x, top + mLineSpac + dayTextLeading, mPaint);
//绘制次数
mPaint.setTextSize(mTextSizePre);
MainJmActivity.DayFinish finish = map.get(day);
String preStr = "0/0";
if(isCurrentMonth){
if(day>currentDay){
mPaint.setColor(mTextColorPreNull);
}else if(finish!=null){
//区分完成未完成
if(finish.finish >= finish.all) {
mPaint.setColor(mTextColorPreFinish);
}else{
mPaint.setColor(mTextColorPreUnFinish);
}
preStr = finish.finish+"/"+finish.all;
}else{
mPaint.setColor(mTextColorPreNull);
}
}else{
if(finish!=null){
//区分完成未完成
if(finish.finish >= finish.all) {
mPaint.setColor(mTextColorPreFinish);
}else{
mPaint.setColor(mTextColorPreUnFinish);
}
preStr = finish.finish+"/"+finish.all;
}else{
mPaint.setColor(mTextColorPreNull);
}
}
len = (int)FontUtil.getFontlength(mPaint, preStr);
x = left + (columnWidth - len)/2;
canvas.drawText(preStr, x, topPre + mTextSpac + preTextLeading, mPaint);
}
}
/**获取月份标题*/
private String getMonthStr(Date month){
SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月");
return df.format(month);
}
private Date str2Date(String str){
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月");
return df.parse(str);
}catch (Exception e){
e.printStackTrace();
return null;
}
}
/****************************事件处理↓↓↓↓↓↓↓****************************/
//焦点坐标
private PointF focusPoint = new PointF();
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
focusPoint.set(event.getX(), event.getY());
touchFocusMove(focusPoint, false);
break;
case MotionEvent.ACTION_MOVE:
focusPoint.set(event.getX(), event.getY());
touchFocusMove(focusPoint, false);
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
focusPoint.set(event.getX(), event.getY());
touchFocusMove(focusPoint, true);
break;
}
return true;
}
/**焦点滑动*/
public void touchFocusMove(final PointF point, boolean eventEnd) {
Log.e(TAG, "点击坐标:("+point.x+" ,"+point.y+"),事件是否结束:"+eventEnd);
/**标题和星期只有在事件结束后才响应*/
if(point.y<=titleHeight){
//事件在标题上
if(eventEnd && listener!=null){
if(point.x>=rowLStart && point.x<(rowLStart+2*mMonthRowSpac+rowWidth)){
Log.w(TAG, "点击左箭头");
listener.onLeftRowClick();
}else if(point.x>rowRStart && point.x<(rowRStart + 2*mMonthRowSpac+rowWidth)){
Log.w(TAG, "点击右箭头");
listener.onRightRowClick();
}else if(point.x>rowLStart && point.x <rowRStart){
listener.onTitleClick(getMonthStr(month), month);
}
}
}else if(point.y<=(titleHeight+weekHeight)){
//事件在星期部分
if(eventEnd && listener!=null){
//根据X坐标找到具体的焦点日期
int xIndex = (int)point.x / columnWidth;
Log.e(TAG, "列宽:"+columnWidth+" x坐标余数:"+(point.x / columnWidth));
if((point.x / columnWidth-xIndex)>0){
xIndex += 1;
}
if(listener!=null){
listener.onWeekClick(xIndex-1, WEEK_STR[xIndex-1]);
}
}
}else{
/**日期部分按下和滑动时重绘,只有在事件结束后才响应*/
touchDay(point, eventEnd);
}
}
//控制事件是否响应
private boolean responseWhenEnd = false;
/**事件点在 日期区域 范围内*/
private void touchDay(final PointF point, boolean eventEnd){
//根据Y坐标找到焦点行
boolean availability = false; //事件是否有效
//日期部分
float top = titleHeight+weekHeight+oneHeight;
int foucsLine = 1;
while(foucsLine<=lineNum){
if(top>=point.y){
availability = true;
break;
}
top += oneHeight;
foucsLine ++;
}
if(availability){
//根据X坐标找到具体的焦点日期
int xIndex = (int)point.x / columnWidth;
if((point.x / columnWidth-xIndex)>0){
xIndex += 1;
}
// Log.e(TAG, "列宽:"+columnWidth+" x坐标余数:"+(point.x / columnWidth));
if(xIndex<=0)
xIndex = 1; //避免调到上一行最后一个日期
if(xIndex>7)
xIndex = 7; //避免调到下一行第一个日期
// Log.e(TAG, "事件在日期部分,第"+foucsLine+"/"+lineNum+"行, "+xIndex+"列");
if(foucsLine == 1){
//第一行
if(xIndex<=firstIndex){
Log.e(TAG, "点到开始空位了");
setSelectedDay(selectDay, true);
}else{
setSelectedDay(xIndex-firstIndex, eventEnd);
}
}else if(foucsLine == lineNum){
//最后一行
if(xIndex>lastLineNum){
Log.e(TAG, "点到结尾空位了");
setSelectedDay(selectDay, true);
}else{
setSelectedDay(firstLineNum + (foucsLine-2)*7+ xIndex, eventEnd);
}
}else{
setSelectedDay(firstLineNum + (foucsLine-2)*7+ xIndex, eventEnd);
}
}else{
//超出日期区域后,视为事件结束,响应最后一个选择日期的回调
setSelectedDay(selectDay, true);
}
}
/**设置选中的日期*/
private void setSelectedDay(int day, boolean eventEnd){
Log.w(TAG, "选中:"+day+" 事件是否结束"+eventEnd);
selectDay = day;
invalidate();
if(listener!=null && eventEnd && responseWhenEnd && lastSelectDay!=selectDay) {
lastSelectDay = selectDay;
listener.onDayClick(selectDay, getMonthStr(month) + selectDay + "日", map.get(selectDay));
}
responseWhenEnd = !eventEnd;
}
/****************************事件处理↑↑↑↑↑↑↑****************************/
@Override
public void invalidate() {
requestLayout();
super.invalidate();
}
/***********************接口API↓↓↓↓↓↓↓**************************/
private Map<Integer, MainJmActivity.DayFinish> map;
public void setRenwu(String month, List<MainJmActivity.DayFinish> list){
setMonth(month);
if(list!=null && list.size()>0){
map.clear();
for(MainJmActivity.DayFinish finish : list){
map.put(finish.day, finish);
}
}
invalidate();
}
public void setRenwu(List<MainJmActivity.DayFinish> list){
if(list!=null && list.size()>0){
map.clear();
for(MainJmActivity.DayFinish finish : list){
map.put(finish.day, finish);
}
}
invalidate();
}
/**月份增减*/
public void monthChange(int change){
Calendar calendar = Calendar.getInstance();
calendar.setTime(month);
calendar.add(Calendar.MONTH, change);
setMonth(getMonthStr(calendar.getTime()));
map.clear();
invalidate();
}
private onClickListener listener;
public void setOnClickListener(onClickListener listener){
this.listener = listener;
}
interface onClickListener{
public abstract void onLeftRowClick();
public abstract void onRightRowClick();
public abstract void onTitleClick(String monthStr, Date month);
public abstract void onWeekClick(int weekIndex, String weekStr);
public abstract void onDayClick(int day, String dayStr, MainJmActivity.DayFinish finish);
}
/***********************接口API↑↑↑↑↑↑↑**************************/
}
CustomCalendar
package com.example.zbytexttwo;
import android.graphics.Paint;
/**
* author : openXu
* create at : 2016/07/8 12:40
* blog : http://blog.csdn.net/xmxkf
* gitHub : https://github.com/openXu
* project : StockChart
* class name : FontUtil
* version : 1.0
* class describe:文字相关处理帮助类
*/
public class FontUtil {
/**
* @param paint
* @param str
* @return 返回指定笔和指定字符串的长度
* @add yujiangtao 16/8/5
*/
public static float getFontlength(Paint paint, String str) {
return paint.measureText(str);
}
/**
* @return 返回指定笔的文字高度
* @add yujiangtao 16/8/5
*/
public static float getFontHeight(Paint paint) {
Paint.FontMetrics fm = paint.getFontMetrics();
return fm.descent - fm.ascent;
}
/**
* @return 返回指定笔离文字顶部的基准距离
* @add yujiangtao 16/8/5
*/
public static float getFontLeading(Paint paint) {
Paint.FontMetrics fm = paint.getFontMetrics();
return fm.leading- fm.ascent;
}
}
FontUtil
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:openxu="http://schemas.android.com/apk/res-auto"
android:id="@+id/tab01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.zbytexttwo.CustomCalendar
android:id="@+id/cal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
openxu:mMonthRowL="@drawable/custom_calendar_row_left"
openxu:mMonthRowR="@drawable/custom_calendar_row_right"
openxu:mMonthRowSpac="20dip"
openxu:mTextSizeMonth="20sp"
openxu:mTextSizeWeek="17sp"
openxu:mTextSizeDay="17sp"
openxu:mTextSizePre="10sp"
openxu:mTextColorMonth="#4b4b4b"
openxu:mTextColorWeek="#9e9e9d"
openxu:mSelectWeekTextColor="#f67633"
openxu:mTextColorDay="#686768"
openxu:mTextColorPreFinish="#fc7451"
openxu:mTextColorPreUnFinish="#60ba8d"
openxu:mTextColorPreNull="#cecdcd"
openxu:mSelectTextColor="#ffffff"
openxu:mMonthSpac="10dip"
openxu:mLineSpac="12dip"
openxu:mTextSpac="8dip"
openxu:mCurrentBg="#6E6E6E"
openxu:mCurrentBgStrokeWidth="1.5dip"
openxu:mCurrentBgDashPath="@array/customCalendar_currentDay_bg_DashPath"
openxu:mSelectBg="#fe7f5c"
openxu:mSelectRadius="15dip" />
<!-- <CalendarView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>-->
</LinearLayout>
</ScrollView>
activity_main_jm
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="customCalendar_currentDay_bg_DashPath">
<item>8</item>
<item>8</item>
<item>8</item>
<item>4</item>
<item>4</item>
<item>4</item>
</array>
</resources>
Array
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomCalendar">
<!--这四个颜色分别是月份、星期、日期、任务的背景色,只是方便调试测量时使用,正式试用时可配置透明色-->
<attr name="mBgMonth" format="color" />
<attr name="mBgWeek" format="color" />
<attr name="mBgDay" format="color" />
<attr name="mBgPre" format="color" />
<attr name="mTextColorMonth" format="color" /> <!--标题字体颜色-->
<attr name="mTextColorWeek" format="color" /> <!--星期字体颜色-->
<attr name="mSelectWeekTextColor" format="color" /> <!--当前星期字体颜色-->
<attr name="mTextColorDay" format="color" /> <!--日期字体颜色-->
<attr name="mTextColorPreFinish" format="color" /> <!--任务次数字体颜色-->
<attr name="mTextColorPreUnFinish" format="color" />
<attr name="mTextColorPreNull" format="color" />
<attr name="mTextSizeMonth" format="dimension" /> <!--标题字体大小-->
<attr name="mTextSizeWeek" format="dimension" /> <!--星期字体大小-->
<attr name="mTextSizeDay" format="dimension" /> <!--日期字体大小-->
<attr name="mTextSizePre" format="dimension" /> <!--任务次数字体大小-->
<attr name="mMonthRowL" format="reference" /> <!--月份箭头-->
<attr name="mMonthRowR" format="reference" /> <!--月份箭头-->
<attr name="mMonthRowSpac" format="dimension" />
<attr name="mSelectTextColor" format="color" /> <!--选中日期字体颜色-->
<attr name="mSelectBg" format="color" /> <!--选中日期背景-->
<attr name="mSelectRadius" format="dimension" /> <!--选中日期背景半径-->
<attr name="mCurrentBg" format="color" /> <!--当天日期背景-->
<attr name="mCurrentBgStrokeWidth" format="dimension" /> <!--当天日期背景虚线宽度-->
<attr name="mCurrentBgDashPath" format="reference" /> <!--当天日期背景虚线数组-->
<attr name="mMonthSpac" format="dimension" /> <!--标题月份上下间隔-->
<attr name="mLineSpac" format="dimension" /> <!--日期行间距-->
<attr name="mTextSpac" format="dimension" /> <!--日期和任务次数字体上下间距-->
</declare-styleable>
</resources>
attrs