android 日历 CalendarView

先上功能图,有图有真相

android 日历 CalendarView_第1张图片

这个日历可以进行多个选择,既可以换的换月,又可以点击换月,还可以选择换年月,日历简洁,对之需要日历选择的app可以做选择。在写这个功能的时候也在网上找了好多,要不就是功能太多,要不就是没有选择年月的,而且大部分都是用ListView或者RecycleView实现的,滑动换月的时候还卡顿。所以最后就自己根据别人的写了一个。

这个日历分为三个部分,一个是头部的年月选择和显示,一个是中间用的ViewPager实现的滑动,ViewPager里面的内容是自己写的一个View,

这里就说说这个自定义View就可以了,首先是画格子,这里星期的格子要比每日的高一些,所以做了一些比例处理,然后就用Path类进行路径处理,都是画一些直线,比较简单,然后就是分为星期字体的显示,这个就纯在一个问题,怎么让它在它的格子中居中,水平居中到还简单,到锤子居中的时候就找了很久,没法,半路搞程序远没有这些基础,实验了各种网上的方法,终于实现了。下面的日期居中方法基本差不多,最大的坑就是选择日期的背景总是不能完全覆盖,总有各种超出,原因是各种设备上面从dp换成px后在分到每个模块的时候总会有小数,最后想了一个办法就是,在给他进行布局测量的时候就让每个模块的大小没有小数,就对其取余,然后减去这部分进行布局,这样分给每个模块就是正数了,就可以完全吻合每个框了。

本来打算加上农历的,那个算法……我不会,又没有找到正确的,就暂时弄了个只有阳历的,等日后加上去。

package com.kxiang.calendar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
 * 项目名称:JobLogging
 * 创建人:kexiang
 * 创建时间:2016/10/25 14:17
 * 

* 单个 layout_height的7.5倍 * 单个 layout_width的7倍 */ public class CalendarSingleView extends View { public CalendarSingleView(Context context, int year, int month, int today) { super(context); init(year, month, today); } // public CalendarSingleView(Context context, AttributeSet attrs) { // super(context, attrs); // init(2016, 10, 25); // } // // public CalendarSingleView(Context context, AttributeSet attrs, int defStyleAttr) { // super(context, attrs, defStyleAttr); // // init(2016, 10, 25); // } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画框 canvas.drawPath(utils.gridPath, utils.gridPaint); //星期水平加垂直居中 Paint.FontMetricsInt fontMetrics = utils.weekPaint.getFontMetricsInt(); float baseline = (utils.weekHeight - fontMetrics.bottom - fontMetrics.top) / 2f; for (int i = 0; i < utils.weekText.length; i++) { if (i == 0 || i == utils.weekText.length - 1) { utils.weekPaint.setColor(utils.weekendColor); } else { utils.weekPaint.setColor(utils.workdayColor); } canvas.drawText(utils.weekText[i], utils.width * (1 + i * 2) / 14f, baseline, utils.weekPaint); } //选中时候的背景 // 按下状态,选择状态背景色 if (today == NO_MONTH && downBgIndex == weakSize) { } else { drawSelectBg(canvas, downBgIndex); } //日期水平加垂直居中 int day = 0; float weakDayOneHight = utils.height * 4 / 5f / 6f; for (int i = 0; i < 6; i++) { float weakDayLine = baseline + utils.weekHeight / 2f + weakDayOneHight * (i * 2 + 1) / 2f; for (int j = 0; j < 7; j++) { int color = utils.noSelectTextColor; if (monthBean.getDay().get(day).isDimBright()) { if (monthBean.getDay().get(day).getSolarCalendar().equals(today + "")) { color = utils.todayTextColor; } else { color = utils.textColor; } } utils.weekDayPaint.setColor(color); canvas.drawText(monthBean.getDay().get(day).getSolarCalendar(), utils.width * (1 + j * 2) / 14f, weakDayLine, utils.weekDayPaint); day++; } } } private void drawSelectBg(Canvas canvas, int index) { int x = getXByIndex(index); int y = getYByIndex(index); float left = utils.singleDayWith * (x - 1) + 1; float top = utils.singleDayHeigh * (y - 1) + utils.weekHeight + 1; canvas.drawRect(left, top, left + utils.singleDayWith - 1, top + utils.singleDayHeigh - 1, utils.selectBgPaint); } private int getXByIndex(int i) { return i % 7 + 1; // 1 2 3 4 5 6 7 } private int getYByIndex(int i) { return i / 7 + 1; // 1 2 3 4 5 6 } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: setSelectedDateByCoor(event.getX(), event.getY()); break; case MotionEvent.ACTION_UP: invalidate(); if (onItemClickListener != null && dayBoolean) { if (monthBean.getDay().get(downDataIndex).isDimBright()) { //响应监听事件 onItemClickListener.OnItemClick(monthBean.getDay(). get(downDataIndex).getSolarCalendar()); } } break; } return true; } private int downDataIndex; private boolean dayBoolean = false; private void setSelectedDateByCoor(float x, float y) { if (y > utils.weekHeight) { dayBoolean = true; int m = (int) (Math.floor(x / utils.singleDayWith) + 1); int n = (int) (Math .floor((y - (utils.weekHeight)) / Float.valueOf(utils.singleDayHeigh)) + 1); downDataIndex = (n - 1) * 7 + m - 1; if (monthBean.getDay().get(downDataIndex).isDimBright()) { downBgIndex = downDataIndex; } } else { dayBoolean = false; } } private class Utils { private String[] weekText = {"星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; private int width; private int height; private float weekHeight; //网格画笔 private Paint gridPaint; //网格路径 private Path gridPath; //星期显示画笔 private Paint weekPaint; //工作日颜色 private int workdayColor = Color.parseColor("#00CD66"); //休息日颜色 private int weekendColor = Color.RED; //具体日期画笔 private Paint weekDayPaint; //当天日期颜色 private int todayTextColor = Color.RED; //当月日期颜色 private int textColor = Color.BLACK; //非当月日期颜色 private int noSelectTextColor = Color.parseColor("#CCCCCC"); //选中背景颜色 private Paint selectBgPaint; private int selectBgColor = Color.parseColor("#99CCFF"); private float singleDayWith; private float singleDayHeigh; void init() { weekHeight = height / 5f; if (weekHeight < width / 6f) { weekHeight = width / 6f; } singleDayHeigh = (height - weekHeight) / 6f; singleDayWith = width / 7f; weekPaint = new Paint(); weekPaint.setColor(Color.BLACK); weekPaint.setAntiAlias(true); weekPaint.setTextSize(width / 6 * 0.28f); weekPaint.setStyle(Paint.Style.FILL); weekPaint.setTextAlign(Paint.Align.CENTER); weekDayPaint = new Paint(); weekDayPaint.setColor(textColor); weekDayPaint.setAntiAlias(true); weekDayPaint.setTextSize(width / 6 * 0.35f); weekDayPaint.setStyle(Paint.Style.FILL); weekDayPaint.setTextAlign(Paint.Align.CENTER); gridPaint = new Paint(); gridPaint.setColor(Color.RED); gridPaint.setStyle(Paint.Style.STROKE); //gridPaint.setStrokeWidth(2); gridPath = new Path(); gridPath.moveTo(0, weekHeight); gridPath.lineTo(utils.width, weekHeight); for (int i = 1; i < 6; i++) { gridPath.moveTo(0, weekHeight + singleDayHeigh * i); gridPath.lineTo(width, weekHeight + singleDayHeigh * i); gridPath.moveTo(singleDayWith * i, 0); gridPath.lineTo(singleDayWith * i, height); } gridPath.moveTo(singleDayWith * 6, 0); gridPath.lineTo(singleDayWith * 6, height); selectBgPaint = new Paint(); selectBgPaint.setAntiAlias(true); selectBgPaint.setStyle(Paint.Style.FILL); selectBgPaint.setColor(selectBgColor); } } private Utils utils; private DataMonthBean monthBean; private SpecialCalendar specialCalendar; private int today; private void init(int year, int month, int today) { this.today = today; utils = new Utils(); specialCalendar = new SpecialCalendar(); monthBean = getCalenderBean(year, month, today); setBackgroundColor(Color.parseColor("#FFFFFF")); } public int getWeek(int y, int m, int d) { if (m < 3) { m += 12; --y; } return (d + 1 + 2 * m + 3 * (m + 1) / 5 + y + (y >> 2) - y / 100 + y / 400) % 7; } private int downBgIndex = 0; // 按下的格子索引 public final static int NO_MONTH = -1; private int weakSize = 0; private DataMonthBean getCalenderBean(int year, int month, int today) { int lastMonth = month - 1; int firstWeak = weakSize = getWeek(year, month, 1); weakSize = downBgIndex = downDataIndex = today + firstWeak - 1; int showMonthDay = specialCalendar.getDaysOfMonth( specialCalendar.isLeapYear(year) , month ); if (specialCalendar.isLeapYear(year) && month == 2) { showMonthDay = specialCalendar.getDaysOfMonth( specialCalendar.isLeapYear(year) , month ); } int lastMonthDay = specialCalendar.getDaysOfMonth( specialCalendar.isLeapYear(year) , lastMonth ) + 1 - firstWeak; if (specialCalendar.isLeapYear(year) && (month - 1) == 2) { lastMonthDay = specialCalendar.getDaysOfMonth( specialCalendar.isLeapYear(year) , lastMonth ) + 1 - firstWeak; } DataMonthBean monthBean = new DataMonthBean(); List beanList = new ArrayList<>(); int next = 1; for (int i = 0; i < 42; i++) { if (firstWeak == 0) { //下个月 if ((i - firstWeak) >= showMonthDay) { DataMonthBean.DayBean dayBean = new DataMonthBean.DayBean(); //这个是设置农历的,犹豫在网上找了好久都没有找到正确的农历算法,暂时没有弄上去 dayBean.setLunarCalendar(""); // lunarCalendar.getLunarDate(lastMonthYear, lastMonth, next, false)); dayBean.setSolarCalendar("" + next); dayBean.setDimBright(false); beanList.add(dayBean); next++; } //当前月 else { DataMonthBean.DayBean dayBean = new DataMonthBean.DayBean(); dayBean.setLunarCalendar(""); // lunarCalendar.getLunarDate(year, month, i + 1, false)); dayBean.setSolarCalendar("" + (i + 1)); dayBean.setDimBright(true); beanList.add(dayBean); } } else { //上个月 if (i < firstWeak) { DataMonthBean.DayBean dayBean = new DataMonthBean.DayBean(); dayBean.setLunarCalendar(""); // lunarCalendar.getLunarDate(lastMonthYear, lastMonth, lastMonthDay, false)); dayBean.setSolarCalendar("" + lastMonthDay); dayBean.setDimBright(false); beanList.add(dayBean); lastMonthDay++; } else { //下个月 if ((i - firstWeak) >= showMonthDay) { DataMonthBean.DayBean dayBean = new DataMonthBean.DayBean(); dayBean.setLunarCalendar(""); // lunarCalendar.getLunarDate(nextMonthYear, nextMonth, next, false)); dayBean.setSolarCalendar("" + next); dayBean.setDimBright(false); beanList.add(dayBean); next++; } //当前月 else { DataMonthBean.DayBean dayBean = new DataMonthBean.DayBean(); dayBean.setLunarCalendar(""); // lunarCalendar.getLunarDate(year, month, // (i + 1 - firstWeak), false)); dayBean.setSolarCalendar("" + (i + 1 - firstWeak)); dayBean.setDimBright(true); beanList.add(dayBean); } } } } monthBean.setDay(beanList); return monthBean; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int tempWidth = MeasureSpec.getSize(widthMeasureSpec); int tempHeight = MeasureSpec.getSize(heightMeasureSpec); //保证每个格子不纯在小数 utils.width = tempWidth - tempWidth % 7; utils.height = tempHeight - tempHeight % 15; widthMeasureSpec = MeasureSpec.makeMeasureSpec(utils.width, MeasureSpec.EXACTLY); heightMeasureSpec = MeasureSpec.makeMeasureSpec(utils.height, MeasureSpec.EXACTLY); setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (changed) { utils.init(); } super.onLayout(changed, left, top, right, bottom); } private OnItemClickListener onItemClickListener; //给控件设置监听事件 public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } //监听接口 public interface OnItemClickListener { void OnItemClick(String date); } }


下面是该项目的个github地址:https://github.com/luck-xiang/CalendarDialog或者点击这里哦 CalendarDialog



你可能感兴趣的:(android)