package com.mingshan.jiepin; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.Calendar; /** * <p>项目名称:jiepin * <p>包 名: com.mingshan.jiepin * <p>版 权: 深圳市铭淏网络科技有限公司 2017 * <p>描 述: * <p>创 建 人: gengmingshan * <p>创建时间: 2018/5>>1)8 14:45 * <p>当前版本: VERSION * <p>修订历史: (版本、修改时间、修改人、修改内容) */ public class CalendarView extends View { final private String[] titleTexts = new String[]{"周日","周一","周二","周三","周四","周五","周六"}; private int[][] showDays;//显示日 private int mCurrYear; private int mCurrMonth; private int mCurrDayOfMonth;//当前时间 private int mSelectYear; private int mSelectMonth; private int mSelectDay;//选中时间 private int mShowYear; private int mShowMonth;//当前展示月 private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private int mTitleRowTextSize = 14; private int mShowDayTextSize = 16; private int mRowSize = 6;//行数 private int mColumnSize = 7;//列数 private int mColumnWidth;//列宽 private int mRowHeight;//行高 private int mMinColumnWidth = dip2px(44); private int mMinColumnHeight = dip2px(36); private int mWidth;//控件宽 private int mHeight;//控件高 private int mOtherMonthColor = Color.parseColor("#44000000"); private int mCurrentMonthColor = Color.parseColor("#99000000"); private int mSelectColor = Color.parseColor("#7744ff88"); private int mCurrentColor = Color.parseColor("#77ff4488"); private Rect mBounds; private int downX; private int downY; private OnSelectItemListener mSelectItemListener; public CalendarView(Context paramContext, AttributeSet paramAttributeSet) { super(paramContext, paramAttributeSet); init(); } private void init() { final Calendar calendar = Calendar.getInstance(); mCurrYear = calendar.get(Calendar.YEAR); mCurrMonth = calendar.get(Calendar.MONTH); mCurrDayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); mSelectYear = mCurrYear; mSelectMonth = mCurrMonth; mSelectDay = mCurrDayOfMonth; mShowYear = mCurrYear; mShowMonth = mCurrMonth; mColumnSize = 7; mPaint = new Paint(); mBounds = new Rect(); mPaint.setTextSize(mTitleRowTextSize); mPaint.getTextBounds("周一", 0, "周一".length(), mBounds); Log.i("init", "mBounds.width():"+mBounds.width()+",mBounds.height()"+mBounds.height()); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.i("onMeasure", "widthMeasureSpec:"+widthMeasureSpec+",heightMeasureSpec:"+heightMeasureSpec); Log.i("onMeasure", "getMeasuredWidth:"+getMeasuredWidth()+",getMeasuredHeight:"+getMeasuredHeight()); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { mWidth = widthSize; mColumnWidth = mWidth/mColumnSize; } else { int columnWidth = 2*mBounds.width(); mColumnWidth = Math.max(mMinColumnWidth, columnWidth); Log.i("onMeasure", "mColumnWidth="+mColumnWidth+",mMinColumnWidth="+mMinColumnWidth); mWidth = getPaddingLeft() + mColumnWidth*mColumnSize + getPaddingRight(); } if (heightMode == MeasureSpec.EXACTLY) { mHeight = heightSize; mRowHeight = mHeight/mRowSize; } else { int columnHeight = 2*mBounds.height(); mRowHeight = Math.max(mMinColumnHeight, columnHeight); Log.i("onMeasure", "mRowHeight="+ mRowHeight +",mMinColumnHeight="+mMinColumnHeight); mHeight = getPaddingTop() + mRowHeight *mRowSize + getPaddingBottom(); } setMeasuredDimension(mWidth, mHeight); Log.i("onMeasure", "mWidth:"+mWidth+",mHeight"+mHeight); } private int dip2px(int paramInt) { float f = getResources().getDisplayMetrics().density; return (int)(paramInt * f + 0.5F); } @Override protected void onDraw(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); final DisplayMetrics metrics = getResources().getDisplayMetrics(); mPaint.setColor(mCurrentMonthColor); mPaint.setTextSize(mTitleRowTextSize*metrics.scaledDensity); // canvas.drawText("啊哈哈哈哈哈",0,mBounds.height(), mPaint); int x; int y; y = getPaddingTop()+ (mRowHeight >>1)+(mBounds.height()>>1); x = getPaddingLeft()+(mColumnWidth>>1)-(mBounds.width()>>1); Log.i("onDraw", "mColumnWidth"+mColumnWidth+",mBounds.width()"+mBounds.width()); Log.i("onDraw", "x"+x); Log.i("onDraw", "mRowHeight"+mRowHeight+",mBounds.height()"+mBounds.height()); Log.i("onDraw", "y"+y); for(int i=0;i<mColumnSize;i++){ canvas.drawText(titleTexts[i],x,y,mPaint); x+=mColumnWidth; } y+= mRowHeight; mPaint.setColor(mOtherMonthColor); final int lastMonthDayCount; final int currentMonthDayCount = getMonthDayCount(mShowYear, mShowMonth); final int firstDayWeek = getFirstDayWeek(mShowYear, mShowMonth); mRowSize = (currentMonthDayCount + firstDayWeek - 1)/mColumnSize + 1; showDays = new int[mRowSize][mColumnSize]; if(mShowMonth==0){ lastMonthDayCount = getMonthDayCount(mShowYear-1, 11); }else { lastMonthDayCount = getMonthDayCount(mShowYear, mShowMonth-1); } mPaint.setTextSize(mShowDayTextSize*metrics.scaledDensity); if(firstDayWeek>1){//开始绘制上月days mPaint.setColor(mOtherMonthColor); } int position; int day; for (int i = 0;i < mRowSize;i++) { for (int j = 0;j<mColumnSize;j++){ position = i*mColumnSize + j; if(position==firstDayWeek-1){//开始绘制当前月days mPaint.setColor(mCurrentMonthColor); }else if(position==firstDayWeek+currentMonthDayCount-1){//开始绘制下月days mPaint.setColor(mOtherMonthColor); } if(position<firstDayWeek-1){ day = lastMonthDayCount - firstDayWeek + 2 + position; }else if(position<firstDayWeek+currentMonthDayCount-1){ day = position - firstDayWeek + 2; }else { day = position - firstDayWeek - currentMonthDayCount + 2; } showDays[i][j] = day; final String dayString = ""+day; Rect bounds = new Rect(); mPaint.getTextBounds(dayString,0,dayString.length(),bounds); x = getPaddingLeft()+j*mColumnWidth+(mColumnWidth>>1)-(bounds.width()>>1); canvas.drawText(day + "", x, y, mPaint); } y+= mRowHeight; } mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(3*metrics.scaledDensity); if(mSelectYear==mShowYear&&mShowMonth==mShowMonth){//画选中日 mPaint.setColor(mSelectColor); int posY = (mSelectDay+firstDayWeek-2)/mColumnSize; int posX = firstDayWeek-2+mSelectDay-posY*mColumnSize; Log.i("onDra--w", "mSelectDay="+mSelectDay); Log.i("onDraw--", "posY="+posY); Log.i("onDra--w", "posX"+posX); canvas.drawCircle(getPaddingLeft()+posX*mColumnWidth+(mColumnWidth>>1), getPaddingTop()+(posY+1)*mRowHeight+(mRowHeight>>1), (mBounds.width()>>1)*metrics.scaledDensity,mPaint); // canvas.draw } if(mCurrYear==mShowYear&&mCurrMonth==mShowMonth){//画当前日 mPaint.setColor(mCurrentColor); int posY = (mCurrDayOfMonth+firstDayWeek-2)/mColumnSize; int posX = firstDayWeek-2+mCurrDayOfMonth-posY*mColumnSize; canvas.drawCircle(getPaddingLeft()+posX*mColumnWidth+(mColumnWidth>>1), getPaddingTop()+(posY+1)*mRowHeight+(mRowHeight>>1), (mBounds.width()>>1)*metrics.scaledDensity,mPaint); } } private int getMonthDayCount(int year, int month) { switch (month + 1) { default: return -1; 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; } } } public static int getFirstDayWeek(int year, int month) { Calendar localCalendar = Calendar.getInstance(); localCalendar.set(year, month, 1); return localCalendar.get(Calendar.DAY_OF_WEEK); } public void showMonth(int year, int month){ mShowYear = year; mShowMonth = month; invalidate(); } public void selectDay(int day){ mSelectYear = mShowYear; mSelectMonth = mShowMonth; mSelectDay = day; invalidate(); } public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = (int)event.getX(); downY = (int)event.getY(); Log.i("ACTION_DOWN", "downX:"+downX+",downY:"+downY); if(downX>getPaddingLeft()&&downX<mWidth-getPaddingRight() &&downY>getPaddingTop()+mRowHeight&&downY<mHeight-getPaddingBottom()){ return true; } break; case MotionEvent.ACTION_UP: int upX = (int)event.getX(); int upY = (int)event.getY(); Log.i("ACTION_UP", "upX:"+upX+",upY:"+upY); if ((Math.abs(upX - downX) < 10) && (Math.abs(upY - downY) < 10)) { // performClick(); doClickAction(downX, downY); return true; } break; } return false; } private void doClickAction(int x, int y) { final int posX = (x-getPaddingLeft())/mColumnWidth; final int posY = (y-getPaddingTop())/mRowHeight-1; final int day = showDays[posY][posX]; Log.i("doClickAction", "posX="+posX+",posY="+posY+",day="+day); final int currentMonthDayCount = getMonthDayCount(mShowYear, mShowMonth); final int firstDayWeek = getFirstDayWeek(mShowYear, mShowMonth); final int position = posY*mColumnSize+posX; if(position<firstDayWeek-1){ showMonth(mShowYear,mShowMonth-1); }else if(position<firstDayWeek-1+currentMonthDayCount){ selectDay(day); if(mSelectItemListener!=null){ mSelectItemListener.onSelect(mSelectYear, mSelectMonth, day); Log.i("onSelect", "onSelect"+day); } }else { showMonth(mShowYear,mShowMonth+1); } } public void setOnSelectItemListener(OnSelectItemListener listener){ mSelectItemListener = listener; } static interface OnSelectItemListener{ void onSelect(int year, int month, int day); } }
需要补充头和事件点展示