标签:android calendar view viewpager 日历
前几天闲来无事,变想做一些小工具玩玩。花了一天多的时间,弄出一个简单日历的View。分为月份模式和星期模式。滚动查看,先上图看看:
上面的是显示的是月份的模式。下面是星期的模式:
一个很简单的自定义View,然后通过Viewpager的OnpageChangeListener进行刷新View的数据。Viewpager通过轮回使用View。我默认设置是5个。可以左右无限切换。
下面是自定义CalendarView:
package com.example.calendar;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class CalendarView extends View {
private static final String TAG = "CalendarView";
/**
* 两种模式 (月份和星期)
*/
public static final int MONTH_STYLE = 0;
public static final int WEEK_STYLE = 1;
private static final int TOTAL_COL = 7;
private static final int TOTAL_ROW = 6;
private Paint mCirclePaint;
private Paint mTextPaint;
private int mViewWidth;
private int mViewHight;
private int mCellSpace;
private Row rows[] = new Row[TOTAL_ROW];
private int mShowYear;//view显示的年份
private int mShowMonth;//view显示的月份
private int mShowDay;//针对星期样式 显示的开始的天
protected int defaultStyle = MONTH_STYLE;
private static final int WEEK = 7;
public CalendarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CalendarView(Context context) {
super(context);
init();
}
public CalendarView(Context context, int style) {
super(context);
this.defaultStyle = style;
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
fillDate();
for (int i = 0; i < TOTAL_ROW; i++) {
if (rows[i] != null)
rows[i].drawCells(canvas, i);
}
}
private void init() {
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.FILL);
mCirclePaint.setColor(Color.parseColor("#F24949"));
initDate();
}
private void initDate(){
if(defaultStyle == MONTH_STYLE){
mShowYear = DateUtil.getYear();
mShowMonth = DateUtil.getMonth();
mShowDay = 1;
}else{
int time[] = DateUtil.getPerviousWeekSunday();
mShowYear = time[0];
mShowMonth = time[1];
mShowDay = time[2];
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHight = h;
mCellSpace = Math.min(mViewHight / TOTAL_ROW, mViewWidth / TOTAL_COL);
mTextPaint.setTextSize(mCellSpace / 3);
}
//组
class Row {
public Cell[] cells = new Cell[TOTAL_COL];
public void drawCells(Canvas canvas, int j) {
for (int i = 0; i < cells.length; i++) {
if (cells[i] != null)
cells[i].drawSelf(canvas, i, j);
}
}
}
//单元格
class Cell {
public String text;
public State state;
public Cell(String text, State state) {
super();
this.text = text;
this.state = state;
}
public void setText(String text) {
this.text = text;
}
//绘制一个单元格 如果颜色需要自定义可以修改
public void drawSelf(Canvas canvas, int i, int j) {
switch (state) {
case CURRENT_MONTH_DAY:
mTextPaint.setColor(Color.parseColor("#80000000"));
break;
case NEXT_MONTH_DAY:
case PAST_MONTH_DAY:
mTextPaint.setColor(Color.parseColor("#40000000"));
break;
case TODAY:
mTextPaint.setColor(Color.parseColor("#fffffe"));
canvas.drawCircle((float) (mCellSpace * (i + 0.45)),
(float) ((j + 0.8) * mCellSpace), mCellSpace / 2,
mCirclePaint);
break;
}
//绘制文字
canvas.drawText(text, i * mCellSpace + mTextPaint.measureText("11"),
(j + 1) * mCellSpace - mTextPaint.measureText(text, 0, 1)
/ 2, mTextPaint);
}
}
enum State {
CURRENT_MONTH_DAY, PAST_MONTH_DAY, NEXT_MONTH_DAY, TODAY;
}
/**
* 填充日期的数据
*/
private void fillDate() {
if (defaultStyle == MONTH_STYLE) {
fillMonthDate();
} else {
fillWeekDate();
}
}
/**
* 填充星期模式下的数据
* 默认通过当前日期得到所在星期天的日期,然后依次填充日期
*/
private void fillWeekDate() {
int currentMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth);
rows[0] = new Row();
if(mShowDay + WEEK -1 > currentMonthDays){
mShowMonth += 1;
}
for (int i = 0; i < TOTAL_COL; i++) {
mShowDay += 1;
if (mShowDay > currentMonthDays) {
mShowDay = 1;
}
if (mShowDay == DateUtil.getCurrentMonthDays()&&
mShowYear == DateUtil.getYear()
&& mShowMonth == DateUtil.getMonth()) {
rows[0].cells[i] = new Cell(mShowDay + "", State.TODAY);
continue;
}
rows[0].cells[i] = new Cell(mShowDay + "", State.CURRENT_MONTH_DAY);
}
}
/**
* 填充月份模式下数据
* 通过getWeekDayFromDate得到一个月第一天是星期几就可以算出所有的日期的位置
* 然后依次填充
*/
private void fillMonthDate() {
int monthDay = DateUtil.getCurrentMonthDays();
int lastMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth - 1);
int currentMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth);
int firstDayWeek = DateUtil.getWeekDayFromDate(mShowYear, mShowMonth);
boolean isCurrentMonth = false;
if (mShowYear == DateUtil.getYear() && mShowMonth == DateUtil.getMonth()) {
isCurrentMonth = true;
}
int time = 0;
for (int j = 0; j < TOTAL_ROW; j++) {
rows[j] = new Row();
for (int i = 0; i < TOTAL_COL; i++) {
int postion = i + j * TOTAL_COL;
if (postion >= firstDayWeek
&& postion < firstDayWeek + currentMonthDays) {
time++;
if (isCurrentMonth && time == monthDay) {
rows[j].cells[i] = new Cell(time + "", State.TODAY);
continue;
}
rows[j].cells[i] = new Cell(time + "",
State.CURRENT_MONTH_DAY);
continue;
} else if (postion < firstDayWeek) {
rows[j].cells[i] = new Cell((lastMonthDays - (firstDayWeek
- postion - 1))
+ "", State.PAST_MONTH_DAY);
continue;
} else if (postion >= firstDayWeek + currentMonthDays) {
rows[j].cells[i] = new Cell((postion - firstDayWeek
- currentMonthDays + 1)
+ "", State.NEXT_MONTH_DAY);
}
}
}
}
//切换pager调用进行刷新
public void update(int year, int month,int day) {
this.mShowMonth = month;
this.mShowYear = year;
this.mShowDay = day;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measure(widthMeasureSpec);
int height = measure(heightMeasureSpec);
int d = Math.min(width, height);
setMeasuredDimension(d, d);
}
protected int measure(int measureSpec) {
int size = MeasureSpec.getSize(measureSpec);
return size;
}
//为了方便viewPager生产出多个的CalendarView
public static CalendarView[] createCalendarViewsForPager(Context context,int count,int style){
CalendarView[] views = new CalendarView[count];
for(int i = 0; i < count;i++){
views[i] = new CalendarView(context, style);
}
return views;
}
public static CalendarView[] createCalendarViewsForPager(Context context,int count){
CalendarView[] views = new CalendarView[count];
for(int i = 0; i < count;i++){
views[i] = new CalendarView(context, CalendarView.MONTH_STYLE);
}
return views;
}
}
我重写了ViewPagerAdapter。CalendarViewPagerAdapter实现了日历所需无限循环的功能,如果想使用就继承它。
package com.example.calendar;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
public class CalendarViewPagerAdapter extends PagerAdapter {
private View[] views;
public CalendarViewPagerAdapter(View[] views) {
super();
this.views = views;
}
@Override
public void finishUpdate(View arg0) {
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public Object instantiateItem(View arg0, int arg1) {
if (((ViewPager) arg0).getChildCount() == views.length) {
((ViewPager) arg0).removeView(views[arg1 % views.length]);
}
((ViewPager) arg0).addView(views[arg1 % views.length], 0);
return views[arg1 % views.length];
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == (arg1);
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void destroyItem(View arg0, int arg1, Object arg2) {
// TODO Auto-generated method stub
}
@Override
public void startUpdate(View arg0) {
}
}
然后为了实现对CalendarView的滑动时的数据更新,我重写了OnPageChangeListener的方法。预留一个方法供activity界面进行回调onPageSelected(int year, int month, int day)。
package com.example.calendar;
import android.support.v4.view.ViewPager.OnPageChangeListener;
public class CalendarViewPagerLisenter implements OnPageChangeListener {
private SildeDirection mDirection = SildeDirection.NO_SILDE;
int mCurrIndex = 498;
private static final int WEEK = 7;
private int mShowYear;
private int mShowMonth;
private int mShowDay = 1;
private CalendarView[] mShowViews;
private int style;
public CalendarViewPagerLisenter(CalendarView[] mShowViews) {
super();
this.mShowViews = mShowViews;
}
public CalendarViewPagerLisenter(CalendarView[] mShowViews, int style) {
super();
this.mShowViews = mShowViews;
this.style = style;
initDate();
}
@Override
public void onPageSelected(int arg0) {
measureDirection(arg0);
updateCalendarView(arg0);
onPageSelected(mShowYear, mShowMonth, mShowDay);
}
private void updateCalendarView(int arg0) {
if (style == CalendarView.MONTH_STYLE)
updateMonthStyleCalendarView();
else if ((style == CalendarView.WEEK_STYLE))
updateWeekStyleCalendarView();
mShowViews[arg0 % mShowViews.length].update(mShowYear, mShowMonth,
mShowDay);
}
private void updateWeekStyleCalendarView() {
//int[] time = new int[3];
if (mDirection == SildeDirection.RIGHT) {
int currentMonthDays = DateUtil.getMonthDays(mShowYear,mShowMonth);
if(mShowDay + WEEK > currentMonthDays){
if(mShowMonth == 12){
mShowMonth = 1;
mShowYear += 1;
}else{
mShowMonth += 1;
}
mShowDay = WEEK -currentMonthDays + mShowDay;
return;
}
mShowDay += WEEK;
} else if (mDirection == SildeDirection.LEFT) {
int lastMonthDays = DateUtil.getMonthDays(mShowYear, mShowMonth);
if(mShowDay - WEEK < 1){
if(mShowMonth == 1){
mShowMonth = 12;
mShowYear -= 1;
}else{
mShowMonth -= 1;
}
mShowDay = lastMonthDays - WEEK + mShowDay;
return;
}
mShowDay -= WEEK;
}
mDirection = SildeDirection.NO_SILDE;
}
private void updateMonthStyleCalendarView() {
if (mDirection == SildeDirection.RIGHT) {
if (mShowMonth == 12) {
mShowMonth = 1;
mShowYear += 1;
} else {
mShowMonth += 1;
}
} else if (mDirection == SildeDirection.LEFT) {
if (mShowMonth == 1) {
mShowMonth = 12;
mShowYear -= 1;
} else {
mShowMonth -= 1;
}
}
mDirection = SildeDirection.NO_SILDE;
}
private void measureDirection(int arg0) {
if (arg0 > mCurrIndex) {
mDirection = SildeDirection.RIGHT;
} else if (arg0 < mCurrIndex) {
mDirection = SildeDirection.LEFT;
}
mCurrIndex = arg0;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
public void onPageSelected(int year, int month, int day) {
}
enum SildeDirection {
RIGHT, LEFT, NO_SILDE;
}
private void initDate(){
if(style == CalendarView.MONTH_STYLE){
mShowYear = DateUtil.getYear();
mShowMonth = DateUtil.getMonth();
mShowDay = 1;
}else if(style == CalendarView.WEEK_STYLE){
int time[] = DateUtil.getPerviousWeekSunday();
mShowYear = time[0];
mShowMonth = time[1];
mShowDay = time[2];
}
onPageSelected(mShowYear, mShowMonth, mShowDay);
}
public void setData(int style, CalendarView[] mShowViews){
this.style = style;
this.mShowViews = mShowViews;
}
}
这是个简单的demo,但是我把他封装起来,直接调用就可以了。如果有需要的同学,可以直接下载就可以了。
下载地址:http://download.csdn.net/detail/huangyanbin123/7707617
标签:android calendar view viewpager 日历
原文地址:http://blog.csdn.net/huangyanbin123/article/details/38350213