Android自定义控件实现可多选课程日历CalendarView
程序员文章站
2023-12-01 10:50:16
可多选课程日历calendarview的效果图
开发环境
ide版本:androidstudio2.0
物理机版本:win7旗舰版(64位)
前言
最近的项...
可多选课程日历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~!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。