可多选课程日历CalendarView的效果图
开发环境
IDE版本:AndroidStudio2.0
物理机版本:Win7旗舰版(64位)
前言
最近的项目中用到了一个课程选择的日历View,于是在网上搜了搜自定义日历View,发现基本上都是单选的,不能够满足项目中的需求。于是自己重新造了个轮子,写了个可以被多选的自定义日历View。最后面会给出GitHub地址。
代码实现
package widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import com.arisaid.calendarview.R;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Created by zhouyou on 2016/7/25.
* Class desc:
*
* 自定义日历View,可多选
*/
public class CalendarView extends View {
// 列的数量
private static final int NUM_COLUMNS = 7;
// 行的数量
private static final int NUM_ROWS = 6;
/**
* 可选日期数据
*/
private List<String> mOptionalDates;
/**
* 以选日期数据
*/
private List<String> mSelectedDates = new ArrayList<>();
// 背景颜色
private int mBgColor = Color.parseColor("#F7F7F7");
// 天数默认颜色
private int mDayNormalColor = Color.parseColor("#0070F8");
// 天数不可选颜色
private int mDayNotOptColor = Color.parseColor("#CBCBCB");
// 天数选择后颜色
private int mDayPressedColor = Color.WHITE;
// 天数字体大小
private int mDayTextSize = 14;
// 是否可以被点击状态
private boolean mClickable = true;
private DisplayMetrics mMetrics;
private Paint mPaint;
private int mCurYear;
private int mCurMonth;
private int mCurDate;
private int mSelYear;
private int mSelMonth;
private int mSelDate;
private int mColumnSize;
private int mRowSize;
private int[][] mDays;
// 当月一共有多少天
private int mMonthDays;
// 当月第一天位于周几
private int mWeekNumber;
// 已选中背景Bitmap
private Bitmap mBgOptBitmap;
// 未选中背景Bitmap
private Bitmap mBgNotOptBitmap;
public CalendarView(Context context) {
super(context);
init();
}
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// 获取手机屏幕参数
mMetrics = getResources().getDisplayMetrics();
// 创建画笔
mPaint = new Paint();
// 获取当前日期
Calendar calendar = Calendar.getInstance();
mCurYear = calendar.get(Calendar.YEAR);
mCurMonth = calendar.get(Calendar.MONTH);
mCurDate = calendar.get(Calendar.DATE);
setSelYTD(mCurYear, mCurMonth, mCurDate);
// 获取背景Bitmap
mBgOptBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_bg_course_optional);
mBgNotOptBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_bg_course_not_optional);
}
@Override
public void invalidate() {
// 避免程序过度绘制
if(hasWindowFocus()) super.invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
initSize();
// 绘制背景
mPaint.setColor(mBgColor);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mPaint);
mDays = new int[6][7];
// 设置绘制字体大小
mPaint.setTextSize(mDayTextSize * mMetrics.scaledDensity);
// 设置绘制字体颜色
String dayStr;
// 获取当月一共有多少天
mMonthDays = DateUtils.getMonthDays(mSelYear, mSelMonth);
// 获取当月第一天位于周几
mWeekNumber = DateUtils.getFirstDayWeek(mSelYear, mSelMonth);
for(int day = 0; day < mMonthDays; day++){
dayStr = String.valueOf(day + 1);
int column = (day + mWeekNumber - 1) % 7;
int row = (day + mWeekNumber - 1) / 7;
mDays[row][column] = day + 1;
int startX = (int) (mColumnSize * column + (mColumnSize - mPaint.measureText(dayStr)) / 2);
int startY = (int) (mRowSize * row + mRowSize / 2 - (mPaint.ascent() + mPaint.descent()) / 2);
// 判断当前天数是否可选
if(mOptionalDates.contains(getSelData(mSelYear, mSelMonth, mDays[row][column]))){
// 可选,继续判断是否是点击过的
if(!mSelectedDates.contains(getSelData(mSelYear, mSelMonth, mDays[row][column]))){
// 没有点击过,绘制默认背景
canvas.drawBitmap(mBgNotOptBitmap, startX - 22, startY - 55, mPaint);
mPaint.setColor(mDayNormalColor);
}else{
// 点击过,绘制点击过的背景
canvas.drawBitmap(mBgOptBitmap, startX - 22, startY - 55, mPaint);
mPaint.setColor(mDayPressedColor);
}
// 绘制天数
canvas.drawText(dayStr, startX, startY - 10, mPaint);
}else{
mPaint.setColor(mDayNotOptColor);
canvas.drawText(dayStr, startX, startY, mPaint);
}
}
}
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:
if(!mClickable) return true;
int upX = (int) event.getX();
int upY = (int) event.getY();
if(Math.abs(upX - downX) < 10 && Math.abs(upY - downY) < 10){
performClick();
onClick((upX + downX) / 2, (upY + downY) / 2);
}
break;
}
return true;
}
/**
* 点击事件
*/
private void onClick(int x, int y){
int row = y / mRowSize;
int column = x / mColumnSize;
setSelYTD(mSelYear, mSelMonth, mDays[row][column]);
// 判断是否点击过
boolean isSelected = mSelectedDates.contains(getSelData(mSelYear, mSelMonth, mSelDate));
if(isSelected){
mSelectedDates.remove(getSelData(mSelYear, mSelMonth, mSelDate));
}else{
mSelectedDates.add(getSelData(mSelYear, mSelMonth, mSelDate));
}
invalidate();
if(mListener != null){
// 执行回调
mListener.onClickDateListener(mSelYear, (mSelMonth + 1), mSelDate);
}
}
/**
* 初始化列宽和高
*/
private void initSize() {
// 初始化每列的大小
mColumnSize = getWidth() / NUM_COLUMNS;
// 初始化每行的大小
mRowSize = getHeight() / NUM_ROWS;
}
/**
* 设置可选择日期
* @param dates 日期数据
*/
public void setOptionalDate(List<String> dates){
this.mOptionalDates = dates;
}
/**
* 设置年月日
* @param year 年
* @param month 月
* @param date 日
*/
public void setSelYTD(int year, int month, int date){
this.mSelYear = year;
this.mSelMonth = month;
this.mSelDate = date;
}
/**
* 设置上一个月日历
*/
public void setLastMonth(){
int year = mSelYear;
int month = mSelMonth;
int day = mSelDate;
// 如果是1月份,则变成12月份
if(month == 0){
year = mSelYear-1;
month = 11;
}else if(DateUtils.getMonthDays(year, month) == day){
// 如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
month = month-1;
day = DateUtils.getMonthDays(year, month);
}else{
month = month-1;
}
setSelYTD(year,month,day);
invalidate();
}
/**
* 设置下一个日历
*/
public void setNextMonth(){
int year = mSelYear;
int month = mSelMonth;
int day = mSelDate;
// 如果是12月份,则变成1月份
if(month == 11){
year = mSelYear+1;
month = 0;
}else if(DateUtils.getMonthDays(year, month) == day){
// 如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
month = month + 1;
day = DateUtils.getMonthDays(year, month);
}else{
month = month + 1;
}
setSelYTD(year,month,day);
invalidate();
}
/**
* 获取当前展示的年和月份
* @return 格式:2016-06
*/
public String getDate(){
String data;
if((mSelMonth + 1) < 10){
data = mSelYear + "-0" + (mSelMonth + 1);
}else{
data = mSelYear + "-" + (mSelMonth + 1);
}
return data;
}
/**
* 获取当前展示的日期
* @return 格式:20160606
*/
private String getSelData(int year, int month, int date){
String monty, day;
month = (month + 1);
// 判断月份是否有非0情况
if((month) < 10) {
monty = "0" + month;
}else{
monty = String.valueOf(month);
}
// 判断天数是否有非0情况
if((date) < 10){
day = "0" + (date);
}else{
day = String.valueOf(date);
}
return year + monty + day;
}
/**
* 获取已选日期数据
*/
public List<String> getSelectedDates(){
return mSelectedDates;
}
/**
* 设置已选日期数据
*/
public void setSelectedDates(List<String> dates){
this.mSelectedDates = dates;
}
/**
* 设置日历是否可以点击
*/
@Override
public void setClickable(boolean clickable) {
this.mClickable = clickable;
}
private OnClickListener mListener;
public interface OnClickListener{
void onClickDateListener(int year, int month, int day);
}
/**
* 设置点击回调
*/
public void setOnClickDate(OnClickListener listener){
this.mListener = listener;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
recyclerBitmap(mBgOptBitmap);
recyclerBitmap(mBgNotOptBitmap);
}
/**
* 释放Bitmap资源
*/
private void recyclerBitmap(Bitmap bitmap) {
if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
}
}
}
使用步骤
1、初始化自定义日历View:
CalendarView mCalendarView = (CalendarView) findViewById(R.id.calendarView);
2、初始化可以被选择的天数数据:
List<String> mDatas = new ArrayList<>();
mDatas.add("20160801");
mDatas.add("20160802");
mDatas.add("20160803");
mDatas.add("20160816");
mDatas.add("20160817");
mDatas.add("20160826");
mDatas.add("20160910");
mDatas.add("20160911");
mDatas.add("20160912");
3、设置给自定义日历View:
// 设置可选日期 mCalendarView.setOptionalDate(mDatas);
设置点击监听
mCalendarView.setOnClickDate(new CalendarView.OnClickListener() {
@Override
public void onClickDateListener(int year, int month, int day) {
Toast.makeText(getApplication(), year + "年" + month + "月" + day + "天", Toast.LENGTH_SHORT).show();
// 获取已选择日期
List<String> dates = mCalendarView.getSelectedDates();
for (String date : dates) {
Log.e("test", "date: " + date);
}
}
});
如果只需要进行数据展示,而不需要点击,可以设置:
// 设置已选日期 mCalendarView.setSelectedDates(mDatas); // 设置不可以被点击 mCalendarView.setClickable(false);
源码下载:
GitHub地址:https://github.com/Airsaid/CalendarView 欢迎star~!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android
# 可多选课程日历
# CalendarView
# Android 一个日历控件的实现代码
# Android开发之日历CalendarView用法示例
# Android实现自定义日历
# android 开发教程之日历项目实践(一)
# android 开发教程之日历项目实践(三)
# android 开发教程之日历项目实践(二)
# Android可签到日历控件的实现方法
# Android实现日历控件示例代码
# Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果
# Android Studio简单实现自定义日历
# 自定义
# 可选
# 当月
# 多选
# 新造
# 回调
# 为该
# 都是
# 判断是否
# 不可以
# 而不
# 上一
# 写了
# 只需要
# 可选择
# 不能够
# 个月
# 大家多多
# 源码下载
# 单选
相关文章:
网站微信制作软件,如何制作微信链接?
网站制作公司排行榜,抖音怎样做个人官方网站
全景视频制作网站有哪些,全景图怎么做成网页?
高端建站如何打造兼具美学与转化的品牌官网?
网站制作说明怎么写,简述网页设计的流程并说明原因?
小型网站建站如何选择虚拟主机?
如何确保FTP站点访问权限与数据传输安全?
建站之星体验版:智能建站系统+响应式设计,多端适配快速建站
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
单页制作网站有哪些,朋友给我发了一个单页网站,我应该怎么修改才能把他变成自己的呢,请求高手指点迷津?
如何破解联通资金短缺导致的基站建设难题?
如何在阿里云香港服务器快速搭建网站?
建站OpenVZ教程与优化策略:配置指南与性能提升
网站建设制作需要多少钱费用,自己做一个网站要多少钱,模板一般多少钱?
如何快速搭建FTP站点实现文件共享?
Python如何创建带属性的XML节点
网站网页制作专业公司,怎样制作自己的网页?
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
建站之星上传入口如何快速找到?
网站制作的步骤包括,正确网址格式怎么写?
成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?
网站制作员失业,怎样查看自己网站的注册者?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
内部网站制作流程,如何建立公司内部网站?
已有域名建站全流程解析:网站搭建步骤与建站工具选择
如何用IIS7快速搭建并优化网站站点?
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
简单实现Android文件上传
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
建站之星如何修改网站生成路径?
建站之星如何保障用户数据免受黑客入侵?
如何在新浪SAE免费搭建个人博客?
建站主机与虚拟主机有何区别?如何选择最优方案?
网站建设制作、微信公众号,公明人民医院怎么在网上预约?
如何在IIS服务器上快速部署高效网站?
建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
香港服务器选型指南:免备案配置与高效建站方案解析
建站主机无法访问?如何排查域名与服务器问题
高防服务器租用如何选择配置与防御等级?
做企业网站制作流程,企业网站制作基本流程有哪些?
已有域名如何免费搭建网站?
西安大型网站制作公司,西安招聘网站最好的是哪个?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
手机网站制作与建设方案,手机网站如何建设?
常州自助建站工具推荐:低成本搭建与模板选择技巧
行程制作网站有哪些,第三方机票电子行程单怎么开?
c++怎么编写动态链接库dll_c++ __declspec(dllexport)导出与调用【方法】
如何通过虚拟主机空间快速建站?
制作网站公司那家好,网络公司是做什么的?
*请认真填写需求信息,我们会在24小时内与您取得联系。