可多選課程日歷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~!
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。
新聞熱點
疑難解答