Calender 是 Android 平台的一个日历显示组件,可以显示一整月历。项目适合初学者学习组件开发,项目如图:
该组件是在ImageView基础上扩展出来的,而Cell 是组件的格子,负责显示日期等。
public class Cell {
private static final String TAG = "Cell";
protected Rect mBound = null;
protected int mDayOfMonth = 1; // from 1 to 31
protected Paint mPaint = new Paint(Paint.SUBPIXEL_TEXT_FLAG
| Paint.ANTI_ALIAS_FLAG);
int dx, dy;
public Cell(int dayOfMon, Rect rect, float textSize, boolean bold) {
mDayOfMonth = dayOfMon;
mBound = rect;
mPaint.setTextSize(textSize/* 26f */);
mPaint.setColor(Color.BLACK);
if (bold)
mPaint.setFakeBoldText(true);
dx = (int) mPaint.measureText(String.valueOf(mDayOfMonth)) / 2;
dy = (int) (-mPaint.ascent() + mPaint.descent()) / 2;
}
public Cell(int dayOfMon, Rect rect, float textSize) {
this(dayOfMon, rect, textSize, false);
}
protected void draw(Canvas canvas) { //自绘
canvas.drawText(String.valueOf(mDayOfMonth), mBound.centerX() - dx,
mBound.centerY() + dy, mPaint);
}
public int getDayOfMonth() { //日期
return mDayOfMonth;
}
public boolean hitTest(int x, int y) { //是否单击
return mBound.contains(x, y);
}
public Rect getBound() { //获取范围
return mBound;
}
public String toString() {
return String.valueOf(mDayOfMonth) + "(" + mBound.toString() + ")";
}
}
关键是CalendarView,它负责布局 显示、操作等工作,源码如下:
public class CalendarView extends ImageView {
private static int WEEK_TOP_MARGIN = 74;
private static int WEEK_LEFT_MARGIN = 40;
private static int CELL_WIDTH = 58;
private static int CELL_HEIGH = 53;
private static int CELL_MARGIN_TOP = 92;
private static int CELL_MARGIN_LEFT = 39;
private static float CELL_TEXT_SIZE;
private static final String TAG = "CalendarView";
private Calendar mRightNow = null;
private Drawable mWeekTitle = null;
private Cell mToday = null;
private Cell[][] mCells = new Cell[6][7];
private OnCellTouchListener mOnCellTouchListener = null;
MonthDisplayHelper mHelper;
Drawable mDecoration = null;
public interface OnCellTouchListener {
public void onTouch(Cell cell);
}
public CalendarView(Context context) {
this(context, null);
}
public CalendarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CalendarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDecoration = context.getResources().getDrawable(
R.drawable.typeb_calendar_today);
initCalendarView();
}
private void initCalendarView() {
mRightNow = Calendar.getInstance();
// prepare static vars
Resources res = getResources();
WEEK_TOP_MARGIN = (int) res.getDimension(R.dimen.week_top_margin);
WEEK_LEFT_MARGIN = (int) res.getDimension(R.dimen.week_left_margin);
CELL_WIDTH = (int) res.getDimension(R.dimen.cell_width);
CELL_HEIGH = (int) res.getDimension(R.dimen.cell_heigh);
CELL_MARGIN_TOP = (int) res.getDimension(R.dimen.cell_margin_top);
CELL_MARGIN_LEFT = (int) res.getDimension(R.dimen.cell_margin_left);
CELL_TEXT_SIZE = res.getDimension(R.dimen.cell_text_size);
// set background
setImageResource(R.drawable.background);
mWeekTitle = res.getDrawable(R.drawable.calendar_week);
mHelper = new MonthDisplayHelper(mRightNow.get(Calendar.YEAR),
mRightNow.get(Calendar.MONTH));
}
private void initCells() {
class _calendar {
public int day;
public boolean thisMonth;
public _calendar(int d, boolean b) {
day = d;
thisMonth = b;
}
public _calendar(int d) {
this(d, false);
}
}
;
_calendar tmp[][] = new _calendar[6][7];
for (int i = 0; i < tmp.length; i++) {
int n[] = mHelper.getDigitsForRow(i);
for (int d = 0; d < n.length; d++) {
if (mHelper.isWithinCurrentMonth(i, d))
tmp[i][d] = new _calendar(n[d], true);
else
tmp[i][d] = new _calendar(n[d]);
}
}
Calendar today = Calendar.getInstance();
int thisDay = 0;
mToday = null;
if (mHelper.getYear() == today.get(Calendar.YEAR)
&& mHelper.getMonth() == today.get(Calendar.MONTH)) {
thisDay = today.get(Calendar.DAY_OF_MONTH);
}
// build cells
Rect Bound = new Rect(CELL_MARGIN_LEFT, CELL_MARGIN_TOP, CELL_WIDTH
+ CELL_MARGIN_LEFT, CELL_HEIGH + CELL_MARGIN_TOP);
for (int week = 0; week < mCells.length; week++) {
for (int day = 0; day < mCells[week].length; day++) {
if (tmp[week][day].thisMonth) {
if (day == 0 || day == 6)
mCells[week][day] = new RedCell(tmp[week][day].day,
new Rect(Bound), CELL_TEXT_SIZE);
else
mCells[week][day] = new Cell(tmp[week][day].day,
new Rect(Bound), CELL_TEXT_SIZE);
} else {
mCells[week][day] = new GrayCell(tmp[week][day].day,
new Rect(Bound), CELL_TEXT_SIZE);
}
Bound.offset(CELL_WIDTH, 0); // move to next column
// get today
if (tmp[week][day].day == thisDay && tmp[week][day].thisMonth) {
mToday = mCells[week][day];
mDecoration.setBounds(mToday.getBound());
}
}
Bound.offset(0, CELL_HEIGH); // move to next row and first column
Bound.left = CELL_MARGIN_LEFT;
Bound.right = CELL_MARGIN_LEFT + CELL_WIDTH;
}
}
@Override
public void onLayout(boolean changed, int left, int top, int right,
int bottom) {
Rect re = getDrawable().getBounds();
WEEK_LEFT_MARGIN = CELL_MARGIN_LEFT = (right - left - re.width()) / 2;
mWeekTitle.setBounds(WEEK_LEFT_MARGIN, WEEK_TOP_MARGIN,
WEEK_LEFT_MARGIN + mWeekTitle.getMinimumWidth(),
WEEK_TOP_MARGIN + mWeekTitle.getMinimumHeight());
initCells();
super.onLayout(changed, left, top, right, bottom);
}
public void setTimeInMillis(long milliseconds) {
mRightNow.setTimeInMillis(milliseconds);
initCells();
this.invalidate();
}
public int getYear() {
return mHelper.getYear();
}
public int getMonth() {
return mHelper.getMonth();
}
public void nextMonth() {
mHelper.nextMonth();
initCells();
invalidate();
}
public void previousMonth() {
mHelper.previousMonth();
initCells();
invalidate();
}
public boolean firstDay(int day) {
return day == 1;
}
public boolean lastDay(int day) {
return mHelper.getNumberOfDaysInMonth() == day;
}
public void goToday() {
Calendar cal = Calendar.getInstance();
mHelper = new MonthDisplayHelper(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH));
initCells();
invalidate();
}
public Calendar getDate() {
return mRightNow;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mOnCellTouchListener != null) {
for (Cell[] week : mCells) {
for (Cell day : week) {
if (day.hitTest((int) event.getX(), (int) event.getY())) {
mOnCellTouchListener.onTouch(day);
}
}
}
}
return super.onTouchEvent(event);
}
public void setOnCellTouchListener(OnCellTouchListener p) {
mOnCellTouchListener = p;
}
@Override
protected void onDraw(Canvas canvas) {
// draw background
super.onDraw(canvas);
mWeekTitle.draw(canvas);
// draw cells
for (Cell[] week : mCells) {
for (Cell day : week) {
day.draw(canvas);
}
}
// draw today
if (mDecoration != null && mToday != null) {
mDecoration.draw(canvas);
}
}
public class GrayCell extends Cell {
public GrayCell(int dayOfMon, Rect rect, float s) {
super(dayOfMon, rect, s);
mPaint.setColor(Color.LTGRAY);
}
}
private class RedCell extends Cell {
public RedCell(int dayOfMon, Rect rect, float s) {
super(dayOfMon, rect, s);
mPaint.setColor(0xdddd0000);
}
}
}
是不是非常简单?