自定义日历视图
- 自定义属性。分别是日期的背景颜色,日期表头的背景颜色,正常的日期字体颜色,当前日期的颜色,当前日期的背景颜色,选择的日期的背景颜色,日期的字体大小,日期表头的字体大小。
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="SunshineView">
- <attr name="android:background"/>
- <attr name="titleBackgroundColor" format="color"/>
- <attr name="normalDateColor" format="color"/>
- <attr name="currentDateColor" format="color"/>
- <attr name="currentDateBackgroundColor" format="color"/>
- <attr name="selectedDateBackgroundColor" format="color"/>
- <attr name="dateSize" format="dimension"/>
- <attr name="titleSize" format="dimension"/>
- </declare-styleable>
- </resources>
- 获取自定义的属性
- //默认的字体大小
- defaultSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 19, getResources().getDisplayMetrics());
- /**
- * 获取自定义属性
- */
- TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.SunshineView,defStyleAttr,0);
- int attrCount = typedArray.getIndexCount();
- for(int i=0; i<attrCount; i++) {
- int attr = typedArray.getIndex(i);
- switch (attr){
- case R.styleable.SunshineView_android_background:
- background = typedArray.getColor(attr,Color.parseColor("#ffec00"));
- break;
- case R.styleable.SunshineView_titleBackgroundColor:
- titleBackgroundColor = typedArray.getColor(attr,0xff0000);
- break;
- case R.styleable.SunshineView_normalDateColor:
- normalColor = typedArray.getColor(attr, 0x232323);
- break;
- case R.styleable.SunshineView_currentDateColor:
- currentColor = typedArray.getColor(attr, 0xffffff);
- break;
- case R.styleable.SunshineView_currentDateBackgroundColor:
- currentBgColor = typedArray.getColor(attr, 0xFFDA4336);
- break;
- case R.styleable.SunshineView_selectedDateBackgroundColor:
- selectedBgColor = typedArray.getColor(attr, 0x7fd2d2d2);
- break;
- case R.styleable.SunshineView_dateSize:
- dateSize = typedArray.getDimensionPixelSize(attr, defaultSize);
- break;
- case R.styleable.SunshineView_titleSize:
- titleSize = typedArray.getDimensionPixelSize(attr,defaultSize);
- break;
- }
- }
- //记得要调用,回收原来的属性
- typedArray.recycle();
- 初始化画笔
- private void initPaint(){
- //星期几标题字体大小
- titleSize = (int) 1.5*defaultSize;
- mTitlePaint = new TextPaint();
- mTitlePaint.setColor(Color.parseColor("#ffffff"));
- mTitlePaint.setTextSize(titleSize);
- mTitlePaint.setStyle(Paint.Style.STROKE);
- mTitlePaint.setTextAlign(Paint.Align.CENTER);
- mTitlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mTitlePaint.setAntiAlias(true);
- mTitlePaint.getTextBounds("22", 0, 2, new Rect());
- //日期的字体大小
- mPaint = new TextPaint();
- mPaint.setColor(normalColor);
- mPaint.setTextSize(dateSize);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mPaint.setTextAlign(Paint.Align.CENTER);
- mPaint.setAntiAlias(true);
- mPaint.getTextBounds("22", 0, 2, new Rect());
- }
- 测量View的大小
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- /**
- * 设置宽度
- */
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- //match_parent
- if (widthMode == MeasureSpec.EXACTLY){
- width = widthSize;
- } else if(widthMode == MeasureSpec.AT_MOST){
- width = getResources().getDisplayMetrics().widthPixels - getPaddingLeft() - getPaddingRight();
- }
- /***
- * 设置高度
- */
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- //match_parent
- if(heightMode == MeasureSpec.EXACTLY){
- height = heightSize;
- }else if(heightMode == MeasureSpec.AT_MOST){
- height = getResources().getDisplayMetrics().heightPixels - getPaddingTop() - getPaddingBottom();
- }
- setMeasuredDimension(width, height);
- }
- 接着就是开始画了
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- drawTitle(canvas);
- drawDate(canvas);
- }
- /**
- * 画表头
- * @param canvas
- */
- private void drawTitle(Canvas canvas){
- float titleHeight = mTitlePaint.measureText("二");
- //画背景
- Paint bgPaint = new Paint();
- bgPaint.setColor(titleBackgroundColor);
- bgPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(getPaddingLeft(), getPaddingTop(), width, height / 7, bgPaint);
- //日期表头
- for(int i=0; i<7; i++){
- canvas.drawText(mTitles[i],(2*i+1)*width/14,height/14+titleHeight/2,mTitlePaint);
- }
- }
- /**
- * 画日期
- * @param canvas
- */
- private void drawDate(Canvas canvas){
- /**
- * 画背景
- */
- Paint paint = new Paint();
- paint.setColor(background);
- paint.setTextSize(titleSize);
- paint.setStyle(Paint.Style.STROKE);
- paint.setFlags(Paint.ANTI_ALIAS_FLAG);
- paint.setAntiAlias(true);
- canvas.drawRect(getPaddingLeft(),height /7,getPaddingRight(),height,paint);
- //当前的日期
- Calendar calendar = Calendar.getInstance();
- int mCurrentDay = calendar.get(Calendar.DAY_OF_MONTH);
- //当前天是星期几
- int currentDayIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
- //获取当月的第一天是星期几
- int firstDayOfMonthIndex = currentDayIndex - (mCurrentDay-1)%7;
- if(firstDayOfMonthIndex<=0){
- firstDayOfMonthIndex = firstDayOfMonthIndex + 7;
- }
- //标记所描绘的日期是星期几
- int dayWeekIndex = firstDayOfMonthIndex;
- //画到了第几行
- int rowIndex = 1;
- int dateHeight = (int) (mPaint.getFontMetrics().ascent+mPaint.getFontMetrics().descent);
- int paddingTop = height/14+height /7;
- int monthDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
- for(int i=1; i<=monthDays; i++){
- if(dayWeekIndex>7){
- dayWeekIndex=1;
- rowIndex= rowIndex+1;
- }
- //先计算这天所要显示的位置
- int positionX = (2*dayWeekIndex-1)*width/14;
- int positionY = (2*rowIndex-1)*height/12 + dateHeight/2 + paddingTop;
- //判断日期是否是当前日期,是的话则画背景的圆,并且设置相应的日期颜色
- if(i!=mCurrentDay){
- //选择其它日期时的背景颜色
- if(i==Integer.parseInt(selectedDate)){
- drawCircle(canvas, positionX, positionY+dateHeight/2, height / 13, selectedBgColor);
- mPaint.setColor(Color.parseColor("#232323"));
- }
- }else {
- drawCircle(canvas, positionX, positionY+dateHeight/2, height / 13, currentBgColor);
- mPaint.setColor(currentColor);
- }
- //画日期和重置字体颜色
- canvas.drawText(i+"",positionX,positionY,mPaint);
- mPaint.setColor(Color.parseColor("#232323"));
- //星期几递增1
- dayWeekIndex++;
- //将日期的信息添加进Map,用来监听点击事件的触发条件
- String dateKey = rowIndex+"_"+dayWeekIndex;
- datePositionMap.put(dateKey, i + "");
- }
- }
- /**
- * 画圆形的背景
- * @param canvas
- * @param positionX
- * @param positionY
- * @param radius
- * @param color
- */
- private void drawCircle(Canvas canvas,int positionX, int positionY, int radius,int color){
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(color);
- canvas.drawCircle(positionX, positionY, radius,mPaint);
- }
- 事件监听
- /**用来监听点击事件
- *
- * @param event
- * @return
- */
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int action = event.getAction();
- if(action==MotionEvent.ACTION_DOWN){
- selectedDate = selectedDate(event);
- if(selectedDate!=null){
- invalidate();
- }else {
- selectedDate="0";
- }
- }
- return true;
- }
- /**
- * 处理单击事件,重绘选中的日期的背景
- * @param event
- * @return
- */
- private String selectedDate(MotionEvent event){
- int paddingTop = height/14+height /7;
- int column = (int)Math.ceil(event.getX()/(width/7))+1;
- int row = (int)Math.ceil((event.getY()-paddingTop)/(height/6));
- String key = row+"_"+column;
- String clickDay = datePositionMap.get(key);
- return clickDay;
- }
- 布局文件
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:sunshine="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <com.sharemebook.myapplication.SunshineView
- android:layout_width="match_parent"
- android:layout_height="282dp"
- android:background="#ffec00"
- sunshine:titleBackgroundColor="#ff0000"
- sunshine:dateSize="15sp"
- sunshine:normalDateColor="#232323"
- sunshine:currentDateColor="#ffffff"
- sunshine:selectedDateBackgroundColor="#7fd2d2d2"
- sunshine:currentDateBackgroundColor="#ff0000"/>
- </LinearLayout>
完整的代码
- /**
- * Created by Sanisy on 2016/3/22.
- */
- public class SunshineView extends View{
- private Paint mTitlePaint;
- private Paint mPaint;
- private int normalColor;
- private int currentColor;
- private int currentBgColor;
- private int selectedBgColor;
- private int dateSize;
- private int background;
- //星期几标签字体设定的大小和默认的字体大小
- private int titleBackgroundColor;
- private int titleSize;
- private int defaultSize;
- private String mTitles[] ={"一","二","三","四","五","六","日"};
- //日历整体的宽度和高度
- private int width;
- private int height;
- //被点击的日期
- private String selectedDate = "0";
- private Map<String,String> datePositionMap = new HashMap<>();
- public SunshineView(Context context) {
- this(context, null);
- }
- public SunshineView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public SunshineView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- //默认的字体大小
- defaultSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 19, getResources().getDisplayMetrics());
- /**
- * 获取自定义属性
- */
- TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.SunshineView,defStyleAttr,0);
- int attrCount = typedArray.getIndexCount();
- for(int i=0; i<attrCount; i++) {
- int attr = typedArray.getIndex(i);
- switch (attr){
- case R.styleable.SunshineView_android_background:
- background = typedArray.getColor(attr,Color.parseColor("#ffec00"));
- break;
- case R.styleable.SunshineView_titleBackgroundColor:
- titleBackgroundColor = typedArray.getColor(attr,0xff0000);
- break;
- case R.styleable.SunshineView_normalDateColor:
- normalColor = typedArray.getColor(attr, 0x232323);
- break;
- case R.styleable.SunshineView_currentDateColor:
- currentColor = typedArray.getColor(attr, 0xffffff);
- break;
- case R.styleable.SunshineView_currentDateBackgroundColor:
- currentBgColor = typedArray.getColor(attr, 0xFFDA4336);
- break;
- case R.styleable.SunshineView_selectedDateBackgroundColor:
- selectedBgColor = typedArray.getColor(attr, 0x7fd2d2d2);
- break;
- case R.styleable.SunshineView_dateSize:
- dateSize = typedArray.getDimensionPixelSize(attr, defaultSize);
- break;
- case R.styleable.SunshineView_titleSize:
- titleSize = typedArray.getDimensionPixelSize(attr,defaultSize);
- break;
- }
- }
- //记得要调用,回收原来的属性
- typedArray.recycle();
- initPaint();
- }
- private void initPaint(){
- //星期几标题字体大小
- titleSize = (int) 1.5*defaultSize;
- mTitlePaint = new TextPaint();
- mTitlePaint.setColor(Color.parseColor("#ffffff"));
- mTitlePaint.setTextSize(titleSize);
- mTitlePaint.setStyle(Paint.Style.STROKE);
- mTitlePaint.setTextAlign(Paint.Align.CENTER);
- mTitlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mTitlePaint.setAntiAlias(true);
- mTitlePaint.getTextBounds("22", 0, 2, new Rect());
- //日期的字体大小
- mPaint = new TextPaint();
- mPaint.setColor(normalColor);
- mPaint.setTextSize(dateSize);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mPaint.setTextAlign(Paint.Align.CENTER);
- mPaint.setAntiAlias(true);
- mPaint.getTextBounds("22", 0, 2, new Rect());
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- /**
- * 设置宽度
- */
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- //match_parent
- if (widthMode == MeasureSpec.EXACTLY){
- width = widthSize;
- } else if(widthMode == MeasureSpec.AT_MOST){
- width = getResources().getDisplayMetrics().widthPixels - getPaddingLeft() - getPaddingRight();
- }
- /***
- * 设置高度
- */
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- //match_parent
- if(heightMode == MeasureSpec.EXACTLY){
- height = heightSize;
- }else if(heightMode == MeasureSpec.AT_MOST){
- height = getResources().getDisplayMetrics().heightPixels - getPaddingTop() - getPaddingBottom();
- }
- setMeasuredDimension(width, height);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- drawTitle(canvas);
- drawDate(canvas);
- }
- /**
- * 画表头
- * @param canvas
- */
- private void drawTitle(Canvas canvas){
- float titleHeight = mTitlePaint.measureText("二");
- //画背景
- Paint bgPaint = new Paint();
- bgPaint.setColor(titleBackgroundColor);
- bgPaint.setStyle(Paint.Style.FILL);
- canvas.drawRect(getPaddingLeft(), getPaddingTop(), width, height / 7, bgPaint);
- //日期表头
- for(int i=0; i<7; i++){
- canvas.drawText(mTitles[i],(2*i+1)*width/14,height/14+titleHeight/2,mTitlePaint);
- }
- }
- /**
- * 画日期
- * @param canvas
- */
- private void drawDate(Canvas canvas){
- /**
- * 画背景
- */
- Paint paint = new Paint();
- paint.setColor(background);
- paint.setTextSize(titleSize);
- paint.setStyle(Paint.Style.STROKE);
- paint.setFlags(Paint.ANTI_ALIAS_FLAG);
- paint.setAntiAlias(true);
- canvas.drawRect(getPaddingLeft(),height /7,getPaddingRight(),height,paint);
- //当前的日期
- Calendar calendar = Calendar.getInstance();
- int mCurrentDay = calendar.get(Calendar.DAY_OF_MONTH);
- //当前天是星期几
- int currentDayIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
- //获取当月的第一天是星期几
- int firstDayOfMonthIndex = currentDayIndex - (mCurrentDay-1)%7;
- if(firstDayOfMonthIndex<=0){
- firstDayOfMonthIndex = firstDayOfMonthIndex + 7;
- }
- //标记所描绘的日期是星期几
- int dayWeekIndex = firstDayOfMonthIndex;
- //画到了第几行
- int rowIndex = 1;
- int dateHeight = (int) (mPaint.getFontMetrics().ascent+mPaint.getFontMetrics().descent);
- int paddingTop = height/14+height /7;
- int monthDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
- for(int i=1; i<=monthDays; i++){
- if(dayWeekIndex>7){
- dayWeekIndex=1;
- rowIndex= rowIndex+1;
- }
- //先计算这天所要显示的位置
- int positionX = (2*dayWeekIndex-1)*width/14;
- int positionY = (2*rowIndex-1)*height/12 + dateHeight/2 + paddingTop;
- //判断日期是否是当前日期,是的话则画背景的圆,并且设置相应的日期颜色
- if(i!=mCurrentDay){
- //选择其它日期时的背景颜色
- if(i==Integer.parseInt(selectedDate)){
- drawCircle(canvas, positionX, positionY+dateHeight/2, height / 13, selectedBgColor);
- mPaint.setColor(Color.parseColor("#232323"));
- }
- }else {
- drawCircle(canvas, positionX, positionY+dateHeight/2, height / 13, currentBgColor);
- mPaint.setColor(currentColor);
- }
- //画日期和重置字体颜色
- canvas.drawText(i+"",positionX,positionY,mPaint);
- mPaint.setColor(Color.parseColor("#232323"));
- //星期几递增1
- dayWeekIndex++;
- //将日期的信息添加进Map,用来监听点击事件的触发条件
- String dateKey = rowIndex+"_"+dayWeekIndex;
- datePositionMap.put(dateKey, i + "");
- }
- }
- /**
- * 画圆形的背景
- * @param canvas
- * @param positionX
- * @param positionY
- * @param radius
- * @param color
- */
- private void drawCircle(Canvas canvas,int positionX, int positionY, int radius,int color){
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(color);
- canvas.drawCircle(positionX, positionY, radius,mPaint);
- }
- /**用来监听点击事件
- *
- * @param event
- * @return
- */
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int action = event.getAction();
- if(action==MotionEvent.ACTION_DOWN){
- selectedDate = selectedDate(event);
- if(selectedDate!=null){
- invalidate();
- }else {
- selectedDate="0";
- }
- }
- return true;
- }
- /**
- * 处理单击事件,重绘选中的日期的背景
- * @param event
- * @return
- */
- private String selectedDate(MotionEvent event){
- int paddingTop = height/14+height /7;
- int column = (int)Math.ceil(event.getX()/(width/7))+1;
- int row = (int)Math.ceil((event.getY()-paddingTop)/(height/6));
- String key = row+"_"+column;
- String clickDay = datePositionMap.get(key);
- return clickDay;
- }
- }