转载

开源项目:单行日历(CalendarView)

项目中需要显示当前月份的一部分日期,笔者不想简单组合几个TextView来实现,花了会时间研究了Google的CalendarView,参考下图的显示效果,定制了一个自己的CalendarView。在摸索的过程中,笔者发现构建CalendarView的复杂之处不在于如何正确地显示最近七天的日期,而在于如何让Canvas绘制的文本能够水平、垂直居中显示。早期,笔者采用了X+N+X=M的模型,即文字占N尺寸,将每个单元格的尺寸M减去N后平分留白空间,但是这种方法首先要求单元格最好是正方形的,然而因为浮点数精确度的问题在平分整个屏幕大小的时候很难做到,最终的显示效果不理想。无奈之下,参考网上的一些方法,得到了相对不错的显示效果。 开源项目:单行日历(CalendarView)
附上详细的CalendarView代码:
  1 /*
  2  * Copyright (C) 2015 Warnier-zhang. All Rights Reserved.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 package org.warnier.zhang.support.v1.widget;
 17 
 18 import android.content.Context;
 19 import android.graphics.Canvas;
 20 import android.graphics.Color;
 21 import android.graphics.Paint;
 22 import android.util.AttributeSet;
 23 import android.view.View;
 24 
 25 import java.util.Calendar;
 26 import java.util.GregorianCalendar;
 27 
 28 /**
 29  * This class is a calendar widget for displaying lastest seven dates in
 30  * a single line. The start of date supported by this CalendarView is
 31  * configurable.
 32  */
 33 public class CalendarView extends View {
 34     private static final int zh_CN = 86;
 35     private static final int en_US = 1;
 36 
 37     private Context mContext;
 38     private Paint mTextPaint;
 39     private Paint mRectPaint;
 40     private Paint mCirclePaint;
 41     private int mWidthMeasureSpec;
 42     private float mCellMeasureSpec;
 43     private String[][] mDataSet = new String[2][7];
 44     private Calendar mCalendar;
 45     private int mDayOfMonth;
 46     private int mDayOfWeek;
 47 
 48     public CalendarView(Context context) {
 49         super(context);
 50         mContext = context;
 51         init();
 52     }
 53 
 54     public CalendarView(Context context, AttributeSet attrs) {
 55         super(context, attrs);
 56         mContext = context;
 57         init();
 58     }
 59 
 60     private void init() {
 61         mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 62         mTextPaint.setTextAlign(Paint.Align.LEFT);
 63         mTextPaint.setTextSize(24);
 64         mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 65         mRectPaint.setStyle(Paint.Style.FILL);
 66         mRectPaint.setColor(Color.parseColor("#4285F4"));
 67         mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 68         mCirclePaint.setStyle(Paint.Style.FILL);
 69         mCirclePaint.setColor(Color.parseColor("#4285F4"));
 70         initDate();
 71     }
 72 
 73     private void initDate() {
 74         mCalendar = new GregorianCalendar();
 75         mDayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH);
 76         mDayOfWeek = mCalendar.get(Calendar.DAY_OF_WEEK);
 77         mDataSet[0] = getWeekdayNames(en_US);
 78         mDataSet[1] = fillDataSet(mDayOfMonth, mDayOfWeek);
 79         if (mDataSet[1] == null) {
 80             throw new IllegalStateException("日期数据异常!");
 81         }
 82     }
 83 
 84     private String[] getWeekdayNames(int locale) {
 85         if (locale == en_US) {
 86             return new String[]{"S", "M", "T", "W", "S", "F", "S"};
 87         } else if (locale == zh_CN) {
 88             return new String[]{"日", "一", "二", "三", "四", "五", "六"};
 89         } else {
 90             throw new IllegalStateException("日期格式异常!");
 91         }
 92     }
 93 
 94     @Override
 95     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 96         super.onSizeChanged(w, h, oldw, oldh);
 97         mWidthMeasureSpec = w;
 98         mCellMeasureSpec = mWidthMeasureSpec / 7.0f;
 99         mTextPaint.setTextSize(mCellMeasureSpec / 3.0f);
100     }
101 
102     @Override
103     protected void onDraw(Canvas canvas) {
104         super.onDraw(canvas);
105         canvas.drawRect(mWidthMeasureSpec, mCellMeasureSpec, 0, 0, mRectPaint);
106         for (int i = 0; i < 2; i++) {
107             setPaintColor(i);
108             for (int j = 0; j < 7; j++) {
109                 float x = (float) ((j + 0.5) * mCellMeasureSpec - mTextPaint.measureText(mDataSet[i][j]) / 2);
110                 float y = (float) ((i + 0.8) * mCellMeasureSpec - mTextPaint.measureText(mDataSet[i][j], 0, 1) / 2);
111                 /**
112                  * 用“圆形”标注当前日期;
113                  */
114                 if (mDataSet[i][j].equals(String.valueOf(mDayOfMonth))) {
115                     float cx = x + mTextPaint.measureText(mDataSet[i][j]) * 0.5f;
116                     float cy = y - mTextPaint.measureText(mDataSet[i][j]) * 0.42f;
117                     canvas.drawCircle(cx, cy, mCellMeasureSpec / 3.0f, mCirclePaint);
118                     setPaintColor(0);
119                     canvas.drawText(mDataSet[i][j], x, y, mTextPaint);
120                     setPaintColor(1);
121                 } else {
122                     canvas.drawText(mDataSet[i][j], x, y, mTextPaint);
123                 }
124             }
125         }
126     }
127 
128     private void setPaintColor(int rowSpec) {
129         if (rowSpec == 0) {
130             mTextPaint.setColor(Color.parseColor("#FFFFFF"));
131         } else {
132             mTextPaint.setColor(Color.parseColor("#565656"));
133         }
134     }
135 
136     private String[] fillDataSet(int dayOfMonth, int dayOfWeek) {
137         int index = 0;
138         String[] date = {
139                 "1", "2", "3", "4", "5", "6", "7"
140         };
141 
142         for (int i = 0; i < date.length; i++) {
143             if (date[i].equals("" + dayOfWeek)) {
144                 date[i] = "" + dayOfMonth;
145                 index = i;
146             }
147         }
148         for (int i = index - 1; i >= 0; i--) {
149             mCalendar.add(Calendar.DAY_OF_MONTH, -1);
150             date[i] = mCalendar.get(Calendar.DAY_OF_MONTH) + "";
151         }
152         mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
153         for (int i = index + 1; i < date.length; i++) {
154             mCalendar.add(Calendar.DAY_OF_MONTH, 1);
155             date[i] = mCalendar.get(Calendar.DAY_OF_MONTH) + "";
156         }
157 
158         return date;
159     }
160 }
当然,CalendarView中存在下述方面的不足: (1)没有添加对layout XML文件的支持; (2)日历每个选项的绘制没有完全水平,垂直居中; (3)两位数和单位数的日期显示间隔,高度不一致; (4)标注当前日期的圆形没能够以字的中心作为圆心; 欢迎各位读者交流心得,共同完善CalendarView。 完整的Android Studio工程下载链接:链接: http://pan.baidu.com/s/1eQAT9ei 密码: 4pqh。 Github链接稍后推送,等待更新...
正文到此结束
Loading...