Android 自定义日历

Posted 风起云涌,勿忘本心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 自定义日历相关的知识,希望对你有一定的参考价值。

好久没来写博客了,这半年多发生了好多的事情,废话不多说,今天在公司里比较闲在,写一篇最近写的公司用到的控件——日历控件。

控件的功能比较少,根据需求只有选择开始时间和结束时间并返回时间段。

效果图如下:

 

第一张图是正常状态下,第二张图是选中了一个开始日期的状态 第三张图片是选择了结束日期。该日历记录的是当前时间的前一个月的时间。

下面为代码:

  1 import android.content.Context;
  2 import android.content.res.TypedArray;
  3 import android.graphics.Canvas;
  4 import android.graphics.Paint;
  5 import android.graphics.Paint.Align;
  6 import android.graphics.Point;
  7 import android.graphics.PorterDuff;
  8 import android.graphics.PorterDuffXfermode;
  9 import android.graphics.Rect;
 10 import android.text.TextUtils;
 11 import android.util.AttributeSet;
 12 import android.util.Log;
 13 import android.view.MotionEvent;
 14 import android.view.View;
 15 
 16 import java.text.SimpleDateFormat;
 17 import java.util.ArrayList;
 18 import java.util.Calendar;
 19 import java.util.Date;
 20 import java.util.List;
 21 
 22 import playrtc.huanhong.com.test.R;
 23 
 24 public class CustomDateView extends View {
 25 
 26     private static final float TITLE_HEIGHT = 200;
 27     private float cellWidth;
 28     private float cellHeight;
 29     private int date[][] = new int[6][7];
 30     private int measuredHeight;
 31     private Point mStartDatePoint;
 32     private Point mEndDatePoint;
 33     private Point mShowMonthPoint;
 34     private Point mLastDayPoint;
 35 
 36     private Paint mNormalTextPaint;
 37     private Paint mTitlePaint;
 38     private Paint mTitleTextPaint;
 39     private Paint mToadyTextPaint;
 40     private Paint mIndicatorPaint;
 41     private Paint mCirclePaintBg;
 42     private Paint mRectPaintBg;
 43     private Paint mCheckedPaint;
 44 
 45     private float mTitleSize = 60;
 46     private float mDateSize = 50;
 47     private float mIndicatorSize = 30;
 48 
 49     private int mTitleBackgroundColor = 0xff047dfe;
 50     private int mTitleTextColor = 0xffffffff;
 51     private int mDateTextColor = 0xff000000;
 52     private int mCheckedTextColor = 0xffffffff;
 53     private int mTodayColor = 0xff047dfe;
 54     private int mIndicatorColor = 0xff000000;
 55     private int mCircleColor = 0xFFff8900;
 56     private int mRectColor = 0xFFffedd9;
 57 
 58     private float mWeekHeight;
 59     private String mDateStr;
 60     private String mCurrentMonthStr;
 61 
 62     private String[] mWeeks = {"日", "一", "二", "三", "四", "五", "六"};
 63     private String[] mMonths = {"一月", "二月", "三月", "四月", "" +
 64             "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
 65     private int mCurrentYear;
 66     private int mCurrentMonth;
 67     private int mCurrentWeek;
 68     private int mCurrentDay;
 69 
 70     private OnCheckedListener mOnCheckedListener;
 71 
 72     public CustomDateView(Context context) {
 73         this(context, null);
 74     }
 75 
 76     public CustomDateView(Context context, AttributeSet attrs) {
 77         super(context, attrs);
 78 //        setCurrentDate(System.currentTimeMillis());
 79         init(attrs);
 80     }
 81 
 82     private void init(AttributeSet attr) {
 83 
 84         TypedArray typedArray = getContext().obtainStyledAttributes(attr, R.styleable.CustomDateView);
 85 
 86         try {
 87             mTitleSize = typedArray.getDimension(R.styleable.CustomDateView_title_text_size, mTitleSize);
 88             mDateSize = typedArray.getDimension(R.styleable.CustomDateView_date_text_size, mDateSize);
 89             mIndicatorSize = typedArray.getDimension(R.styleable.CustomDateView_indicator_text_size, mIndicatorSize);
 90 
 91             mTitleBackgroundColor = typedArray.getColor(R.styleable.CustomDateView_title_background_color, mTitleBackgroundColor);
 92             mTitleTextColor = typedArray.getColor(R.styleable.CustomDateView_title_text_color, mTitleTextColor);
 93             mDateTextColor = typedArray.getColor(R.styleable.CustomDateView_date_text_color, mDateTextColor);
 94             mCheckedTextColor = typedArray.getColor(R.styleable.CustomDateView_checked_text_color, mCheckedTextColor);
 95             mTodayColor = typedArray.getColor(R.styleable.CustomDateView_today_text_color, mTodayColor);
 96             mIndicatorColor = typedArray.getColor(R.styleable.CustomDateView_indicator_text_color, mIndicatorColor);
 97             mCircleColor = typedArray.getColor(R.styleable.CustomDateView_checked_circle_color, mCircleColor);
 98             mRectColor = typedArray.getColor(R.styleable.CustomDateView_checked_background_color, mRectColor);
 99         } catch (Exception e) {
100             e.printStackTrace();
101         } finally {
102             typedArray.recycle();
103         }
104 
105 
106         //上部蓝色
107         mTitlePaint = new Paint();
108         mTitlePaint.setAntiAlias(true);
109         mTitlePaint.setColor(mTitleBackgroundColor);
110 
111         //上部文字
112         mTitleTextPaint = new Paint();
113         mTitleTextPaint.setColor(mTitleTextColor);
114         mTitleTextPaint.setAntiAlias(true);
115         mTitleTextPaint.setTextSize(mTitleSize);
116         mTitleTextPaint.setTextAlign(Align.CENTER);
117 
118         //其他文字
119         mNormalTextPaint = new Paint();
120         mNormalTextPaint.setColor(mDateTextColor);
121         mNormalTextPaint.setTextAlign(Align.CENTER);
122         mNormalTextPaint.setAntiAlias(true);
123         mNormalTextPaint.setTextSize(mDateSize);
124 
125         //选中文字
126         mCheckedPaint = new Paint();
127         mCheckedPaint.setColor(mCheckedTextColor);
128         mCheckedPaint.setTextAlign(Align.CENTER);
129         mCheckedPaint.setAntiAlias(true);
130         mCheckedPaint.setTextSize(mDateSize);
131 
132         //今天显示的字体
133         mToadyTextPaint = new Paint();
134         mToadyTextPaint.setAntiAlias(true);
135         mToadyTextPaint.setTextAlign(Align.CENTER);
136         mToadyTextPaint.setColor(mTodayColor);
137         mToadyTextPaint.setTextSize(mDateSize);
138 
139         //交界处显示的字体
140         mIndicatorPaint = new Paint();
141         mIndicatorPaint.setAntiAlias(true);
142         mIndicatorPaint.setTextAlign(Align.CENTER);
143         mIndicatorPaint.setColor(mIndicatorColor);
144         mIndicatorPaint.setTextSize(mIndicatorSize);
145 
146         //圆形
147         mCirclePaintBg = new Paint();
148         mCirclePaintBg.setColor(mCircleColor);
149         mCirclePaintBg.setAntiAlias(true);
150 
151         //矩形
152         mRectPaintBg = new Paint();
153         mRectPaintBg.setColor(mRectColor);
154         mRectPaintBg.setAntiAlias(true);
155     }
156 
157     @Override
158     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
159         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
160         cellWidth = (getMeasuredWidth() - getPaddingLeft() - getPaddingRight()) / date[0].length;
161         mWeekHeight = cellWidth;
162         cellHeight = (cellWidth + mIndicatorSize);
163         measuredHeight = (int) (cellHeight * (date.length + 1) + TITLE_HEIGHT + getPaddingBottom());
164         setMeasuredDimension(widthMeasureSpec, measuredHeight);
165     }
166 
167     @Override
168     protected void onDraw(Canvas canvas) {
169         drawRect(canvas);
170         drawCircle(canvas);
171 
172         mTitlePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
173         canvas.drawRect(0, 0, getMeasuredWidth(), TITLE_HEIGHT, mTitlePaint);
174 
175         Rect rect = new Rect();
176         Rect rectWeek = new Rect();
177 
178         if (!TextUtils.isEmpty(mDateStr)) {
179             mTitleTextPaint.getTextBounds(mDateStr, 0, mDateStr.length(), rect);
180             canvas.drawText(mDateStr, getMeasuredWidth() / 2, TITLE_HEIGHT / 2 + rect.height() / 2,
181                     mTitleTextPaint);
182         }
183 
184         drawWeekText(canvas, rectWeek);
185 
186         drawDateText(canvas, rect);
187 
188         if (!TextUtils.isEmpty(mCurrentMonthStr)) {
189             mIndicatorPaint.getTextBounds(mCurrentMonthStr, 0, mCurrentMonthStr.length(), rect);
190         }
191 
192         if (mShowMonthPoint != null) {
193             canvas.drawText(mCurrentMonthStr,
194                     mShowMonthPoint.x * cellWidth + cellWidth / 2 + getPaddingLeft(),
195                     (mShowMonthPoint.y + 1) * cellHeight + mWeekHeight + rect.height() / 4 + TITLE_HEIGHT, mIndicatorPaint);
196         }
197 //        //竖线
198 //        for (int i = 0; i <= date[0].length; i++) {
199 //            canvas.drawLine(i * cellWidth + getPaddingLeft(), TITLE_HEIGHT, i * cellWidth + getPaddingLeft(), measuredHeight - getPaddingBottom(), mNormalTextPaint);
200 //        }
201 //
202 //        //横线
203 //        for (int i = 0; i < date.length; i++) {
204 //            canvas.drawLine(getPaddingLeft(), i * cellHeight + TITLE_HEIGHT + mWeekHeight, getMeasuredWidth() - getPaddingRight(),
205 //                    i * cellHeight + mWeekHeight + TITLE_HEIGHT, mNormalTextPaint);
206 //        }
207     }
208 
209     /**
210      * @param canvas   画布
211      * @param rectWeek 测量文字长宽矩形
212      */
213     private void drawWeekText(Canvas canvas, Rect rectWeek) {
214         int maxHeight = 0;
215         //获得最高的文字高度
216         for (int k = 0; k < mWeeks.length; k++) {
217             mNormalTextPaint.getTextBounds(mWeeks[k], 0, mWeeks[k].length(), rectWeek);
218             if (rectWeek.height() > maxHeight) {
219                 maxHeight = rectWeek.height();
220             }
221         }
222 
223         for (int k = 0; k < mWeeks.length; k++) {
224             canvas.drawText(mWeeks[k],
225                     k * cellWidth + cellWidth / 2 + getPaddingLeft(),
226                     mWeekHeight / 2 + maxHeight / 2 + TITLE_HEIGHT, mNormalTextPaint);
227         }
228     }
229 
230     /**
231      * @param canvas 画布
232      * @param rect   测量文字长宽矩形
233      */
234     private void drawDateText(Canvas canvas, Rect rect) {
235         for (int i = 0; i < date.length; i++) {
236             for (int j = 0; j < date[0].length; j++) {
237 
238                 mNormalTextPaint.getTextBounds(date[i][j] + "", 0, String.valueOf(date[i][j]).length(), rect);
239 
240                 if (date[i][j] != 0) {
241 
242                     if (i == mLastDayPoint.x && j == mLastDayPoint.y) {
243                         canvas.drawText(date[i][j] + "",
244                                 j * cellWidth + cellWidth / 2 + getPaddingLeft(),
245                                 i * cellHeight + cellHeight / 2 + mWeekHeight + rect.height() / 2 + TITLE_HEIGHT, mToadyTextPaint);
246                     } else {
247 
248                         if ((mStartDatePoint != null && i == mStartDatePoint.y && j == mStartDatePoint.x) || (mEndDatePoint != null && i == mEndDatePoint.y && j == mEndDatePoint.x)) {
249                             canvas.drawText(date[i][j] + "",
250                                     j * cellWidth + cellWidth / 2 + getPaddingLeft(),
251                                     i * cellHeight + cellHeight / 2 + mWeekHeight + rect.height() / 2 + TITLE_HEIGHT, mCheckedPaint);
252                         } else {
253                             canvas.drawText(date[i][j] + "",
254                                     j * cellWidth + cellWidth / 2 + getPaddingLeft(),
255                                     i * cellHeight + cellHeight / 2 + mWeekHeight + rect.height() / 2 + TITLE_HEIGHT, mNormalTextPaint);
256                         }
257                     }
258                 }
259 
260             }
261         }
262     }
263 
264     @Override
265     public boolean onTouchEvent(MotionEvent event) {
266 
267         switch (event.getAction()) {
268             case MotionEvent.ACTION_DOWN:
269 
270                 if (mStartDatePoint != null && mEndDatePoint != null) {
271                     break;
272                 }
273 
274                 if (mStartDatePoint == null) {
275                     if (getPoint(event.getX(), event.getY()) != null) {
276                         mStartDatePoint = getPoint(event.getX(), event.getY());
277                     }
278                 } else {
279                     Point point1 = getPoint(event.getX(), event.getY());
280                     if (point1 != null) {
281                         if (point1.y < mStartDatePoint.y) {
282                             mStartDatePoint = point1;
283                         } else if (point1.x <= mStartDatePoint.x && point1.y == mStartDatePoint.y) {
284                             mStartDatePoint = point1;
285                         } else {
286                             mEndDatePoint = point1;
287 
288                             if (mOnCheckedListener != null) {
289                                 mOnCheckedListener.onChecked();
290                             }
291 
292                         }
293                     }
294                 }
295 
296                 invalidate();
297                 break;
298 
299             default:
300                 break;
301         }
302         return true;
303     }
304 
305     private Point getPoint(float x, float y) {
306         Point point = new Point();
307         point.x = (int) ((x - getPaddingLeft()) / cellWidth);
308         point.y = (int) ((y - TITLE_HEIGHT - mWeekHeight) / cellHeight);
309 
310         Log.d("fxxk", "进入getPoint x = " + point.x + "y = " + point.y);
311         if (point.y < date.length && point.x < date[0].length && point.y >= 0 && point.x >= 0) {
312             if (date[point.y][point.x] == 0) {
313                 return null;
314             }
315         } else {
316             return null;
317         }
318 
319         return point;
320 
321     }
322 
323     private void drawCircle(Canvas canvas) {
324         if (mStartDatePoint != null) {
325             canvas.drawCircle(mStartDatePoint.x * cellWidth + cellWidth / 2 + getPaddingLeft(), mStartDatePoint.y * cellHeight + cellHeight / 2 + mWeekHeight + TITLE_HEIGHT,
326                     (float) (cellHeight * 0.3), mCirclePaintBg);
327         }
328 
329         if (mEndDatePoint != null) {
330             canvas.drawCircle(mEndDatePoint.x * cellWidth + cellWidth / 2 + getPaddingLeft(),
331                     mEndDatePoint.y * cellHeight + cellHeight / 2 + mWeekHeight + TITLE_HEIGHT, (float) (cellHeight * 0.3), mCirclePaintBg);
332         }
333     }
334 
335     private void drawRect(Canvas canvas) {
336         if (mEndDatePoint != null && mStartDatePoint != null) {
337 
338             int total = date[0].length - mStartDatePoint.x + 1 + (mEndDatePoint.y - mStartDatePoint.y) * date[0].length - date[0].length + mEndDatePoint.x;
339             int beginX = mStartDatePoint.x;
340             int beginY = mStartDatePoint.y;
341             for (int i = 0; i < total; i++) {
342 
343                 if (i == 0) {
344                     canvas.drawRect(beginX * cellWidth + cellWidth / 2 + getPaddingLeft(), (float) (beginY * cellHeight + TITLE_HEIGHT + mWeekHeight + 0.21 * cellHeight),
345                             beginX * cellWidth + cellWidth + getPaddingLeft(), (float) (beginY * cellHeight + cellHeight + mWeekHeight + TITLE_HEIGHT - 0.21 * cellHeight), mRectPaintBg);
346                 } else if (i == total - 1) {
347                     canvas.drawRect(beginX * cellWidth + getPaddingLeft(), (float) (beginY * cellHeight + TITLE_HEIGHT + mWeekHeight + 0.21 * cellHeight),
348                             beginX * cellWidth + cellWidth / 2 + getPaddingLeft(), (float) (beginY * cellHeight + cellHeight + mWeekHeight + TITLE_HEIGHT - 0.21 * cellHeight),
349                             mRectPaintBg);
350                 } else {
351                     canvas.drawRect(beginX * cellWidth + getPaddingLeft(), (float) (beginY * cellHeight + TITLE_HEIGHT + mWeekHeight + 0.21 * cellHeight),
352                             beginX * cellWidth + cellWidth + getPaddingLeft(), (float) (beginY * cellHeight + cellHeight + mWeekHeight + TITLE_HEIGHT - 0.21 * cellHeight), mRectPaintBg)
353                     ;
354                 }
355                 beginX++;
356                 if (beginX % date[0].length == 0) {
357                     beginX = 0;
358                     beginY++;
359                 }
360 
361             }
362         }
363     }
364 
365     private int distance(Point point1, Point point2) {
366         int count = 0;
367 
368         if (point2.y > point1.y) {
369             count = date.length - point1.x + 1 + (point2.y - point1.y) * date.length - date.length + point2.x;
370         } else if (point2.y == point1.y) {
371             count = Math.abs(point2.x - point1.x);
372         } else if (point2.y < point1.y) {
373             count = date.length - point2.x + 1 + (point1.y - point2.y) * date.length - date.length + point1.x;
374         }
375 
376         return count;
377     }
378 
379     /**
380      * 设置当前时间
381      */
382     public void setCurrentDate(long time) {
383         Date date1 = new Date(time);
384 
385         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
386         mDateStr = dateFormat.format(date1);
387 
388         Calendar calendar = Calendar.getInstance();
389         calendar.setTime(date1);
390         mCurrentYear = calendar.get(Calendar.YEAR);
391         mCurrentMonth = calendar.get(Calendar.MONTH);
392         mCurrentWeek = calendar.get(Calendar.DAY_OF_WEEK);
393         mCurrentDay = calendar.get(Calendar.DAY_OF_MONTH);
394         mCurrentMonthStr = mMonths[mCurrentMonth];
395 
396         if (mCurrentWeek <= 2) {
397             date = new int[6][7];
398         } 以上是关于Android 自定义日历的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义可标记日历

Android - 如何将自定义对象传递给片段

从android中的片段更改自定义ActionBar标题

片段中ListView的android自定义适配器

为 iOS 和 Android 自定义日历

Android自定义View(CustomCalendar-定制日历控件)