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 自定义日历的主要内容,如果未能解决你的问题,请参考以下文章