公司项目需要一个功能全面的日历,然后就在网上找demo,然后根据demo自己深度定制了一个日历,基本满足了需求,现在把日历核心代码共享给大家。源码下载地址http://download.csdn.net/detail/voidmain_123/9275921
CollapseCalendarView.java
只需要将该控件引入到布局文件中
package com.eroad.widget.calendar;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import org.joda.time.LocalDate;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.eroad.widget.calendar.manager.CalendarManager;
import com.eroad.widget.calendar.manager.CalendarManager.State;
import com.eroad.widget.calendar.manager.Day;
import com.eroad.widget.calendar.manager.Month;
import com.eroad.widget.calendar.manager.ResizeManager;
import com.eroad.widget.calendar.manager.Week;
import com.eroad.widget.calendar.widget.DayView;
import com.eroad.widget.calendar.widget.WeekView;
import com.example.calendarnew.R;
/**
* 日历View
* @author MaJian
*
*/
@SuppressLint({ “SimpleDateFormat”, “NewApi” }) public class CollapseCalendarView extends LinearLayout implements View.OnClickListener {
public static final String TAG = "CalendarView";
private CalendarManager mManager;
private TextView mTitleView;
private ImageButton mPrev;
private ImageButton mNext;
private LinearLayout mWeeksView;
private final LayoutInflater mInflater;
private final RecycleBin mRecycleBin = new RecycleBin();
private OnDateSelect mListener;
private TextView mSelectionText;
private LinearLayout mHeader;
private ResizeManager mResizeManager;
private ImageView mIvPre;
private ImageView mIvNext;
private Animation left_in;
private Animation right_in;
private boolean initialized;
private String[] weeks;
private OnTitleClickListener titleClickListener;
private JSONObject dataObject; //日历数据源
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
private boolean showChinaDay = true; //是否显示农历日期
public CollapseCalendarView(Context context) {
this(context, null);
onFinishInflate();
}
public void showChinaDay(boolean showChinaDay){
this.showChinaDay = showChinaDay;
populateLayout();
}
/**
* 设置标题点击监听器
* @param titleClickListener
*/
public void setTitleClickListener(OnTitleClickListener titleClickListener){
this.titleClickListener = titleClickListener;
}
public CollapseCalendarView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.calendarViewStyle);
}
public void setArrayData(JSONObject jsonObject){
this.dataObject = jsonObject;
}
public interface OnTitleClickListener{
public void onTitleClick();
}
@SuppressLint("NewApi")
public CollapseCalendarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
weeks = getResources().getStringArray(R.array.weeks);
mInflater = LayoutInflater.from(context);
mResizeManager = new ResizeManager(this);
inflate(context, R.layout.calendar_layout, this);
setOrientation(VERTICAL);
setBackgroundColor(getResources().getColor(R.color.cal_color_white));
mIvPre = new ImageView(getContext());
mIvNext = new ImageView(getContext());
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT);
mIvPre.setLayoutParams(param);
mIvNext.setLayoutParams(param);
initAnim();
}
/**
* 初始化左右滑动动画
*/
private void initAnim(){
left_in = AnimationUtils.makeInAnimation(getContext(), true);
right_in = AnimationUtils.makeInAnimation(getContext(), false);
}
/**
* 初始化日历管理器
* @param manager 日历管理器对象
*/
public void init(CalendarManager manager) {
if (manager != null) {
mManager = manager;
if (mListener != null) {
mListener.onDateSelected(mManager.getSelectedDay());
}
populateLayout();
}
}
/**
* 切换到指定某天界面
* @param date yyyy-MM-dd
*/
public void changeDate(String date){
if (date.compareTo(mManager.getSelectedDay().toString()) > 0) {
this.setAnimation(right_in);
right_in.start();
} else if (date.compareTo(mManager.getSelectedDay().toString()) < 0) {
this.setAnimation(left_in);
left_in.start();
}
try {
mManager.init(LocalDate.fromDateFields(sdf.parse(date)));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
init(mManager);
}
public CalendarManager getManager() {
return mManager;
}
@Override
public void onClick(View v) {
if (mManager != null) {
int id = v.getId();
if (id == R.id.prev) {
prev();
} else if (id == R.id.next) {
next();
} else if (id == R.id.title) {
if (titleClickListener != null) {
titleClickListener.onTitleClick();
}
}
}
}
@SuppressLint("WrongCall")
@Override
protected void dispatchDraw( Canvas canvas) {
mResizeManager.onDraw();
super.dispatchDraw(canvas);
}
public CalendarManager.State getState() {
if (mManager != null) {
return mManager.getState();
} else {
return null;
}
}
public void setDateSelectListener(OnDateSelect listener) {
mListener = listener;
}
/**
* 设置日历标题
* @param text
*/
public void setTitle(String text) {
if (TextUtils.isEmpty(text)) {
mHeader.setVisibility(View.VISIBLE);
mSelectionText.setVisibility(View.GONE);
} else {
mHeader.setVisibility(View.GONE);
mSelectionText.setVisibility(View.VISIBLE);
mSelectionText.setText(text);
}
}
/**
* 显示日历自带标题
*/
public void showHeader(){
mHeader.setVisibility(View.VISIBLE);
}
/**
* 隐藏日历自带标题
*/
public void hideHeader(){
mHeader.setVisibility(View.GONE);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mResizeManager.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent( MotionEvent event) {
super.onTouchEvent(event);
return mResizeManager.onTouchEvent(event);
}
/**
* 周-月
*/
public void weekToMonth(){
if (mManager.getState() == CalendarManager.State.WEEK) {
mManager.toggleView();
}
}
/**
* 月-周
*/
public void monthToWeek(){
if (mManager.getState() == CalendarManager.State.MONTH) {
mManager.toggleView();
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTitleView = (TextView) findViewById(R.id.title);
mTitleView.setOnClickListener(this);
mPrev = (ImageButton) findViewById(R.id.prev);
mNext = (ImageButton) findViewById(R.id.next);
mWeeksView = (LinearLayout) findViewById(R.id.weeks);
mHeader = (LinearLayout) findViewById(R.id.header);
mSelectionText = (TextView) findViewById(R.id.selection_title);
mPrev.setOnClickListener(this);
mNext.setOnClickListener(this);
populateLayout();
}
/**
* 绘制日历周标题
*/
private void populateDays() {
if (!initialized) {
CalendarManager manager = getManager();
if (manager != null) {
LinearLayout layout = (LinearLayout) findViewById(R.id.days);
for (int i = 0; i < 7; i++) {
TextView textView = (TextView) layout.getChildAt(i);
textView.setText(weeks[i]);
if (i > 4) {
textView.setTextColor(getResources().getColor(R.color.cal_blue_dark));
}
}
initialized = true;
}
}
}
/**
* 刷新日历View
*/
public synchronized void populateLayout() {
if (mManager != null) {
populateDays();
if (mPrev != null) {
mPrev.setEnabled(mManager.hasPrev());
mNext.setEnabled(mManager.hasNext());
mTitleView.setText(mManager.getHeaderText());
if (mManager.getState() == CalendarManager.State.MONTH) {
populateMonthLayout((Month) mManager.getUnits());
} else {
populateWeekLayout((Week) mManager.getUnits());
}
}
}
}
/**
* 刷新日历Month View
* @param month 月份
*/
private void populateMonthLayout(Month month) {
List<Week> weeks = month.getWeeks();
int cnt = weeks.size();
for (int i = 0; i < cnt; i++) {
WeekView weekView = getWeekView(i);
populateWeekLayout(weeks.get(i), weekView);
}
int childCnt = mWeeksView.getChildCount();
if (cnt < childCnt) {
for (int i = cnt; i < childCnt; i++) {
cacheView(i);
}
}
}
/**
* 刷新日历Week View
* @param week 周
*/
private void populateWeekLayout(Week week) {
WeekView weekView = getWeekView(0);
populateWeekLayout(week, weekView);
int cnt = mWeeksView.getChildCount();
if (cnt > 1) {
for (int i = cnt - 1; i > 0; i--) {
cacheView(i);
}
}
}
private void populateWeekLayout( Week week, WeekView weekView) {
List<Day> days = week.getDays();
for (int i = 0; i < 7; i++) {
final Day day = days.get(i);
LinearLayout layout = (LinearLayout) weekView.getChildAt(i);
DayView dayView = (DayView) layout.findViewById(R.id.tvDayView);
DayView chinaDay = (DayView) layout.findViewById(R.id.tvChina);
if (showChinaDay) {
chinaDay.setVisibility(View.VISIBLE);
} else {
chinaDay.setVisibility(View.GONE);
}
View viewPoint = layout.findViewById(R.id.view_point);
TextView tvDayType = (TextView) layout.findViewById(R.id.tv_day_type);
//渲染日期上班休假类型
if (dataObject != null && dataObject.optJSONObject(sdf.format(day.getDate().toDate())) != null) {
JSONObject jsonObject = dataObject.optJSONObject(sdf.format(day.getDate().toDate()));
if (!TextUtils.isEmpty(jsonObject.optString("type"))) {
tvDayType.setText(jsonObject.optString("type"));
tvDayType.setVisibility(View.VISIBLE);
if (jsonObject.optString("type").equals("假")) {
tvDayType.setBackground(getResources().getDrawable(R.drawable.bg_day_type_red));
} else if (jsonObject.optString("type").equals("班")) {
tvDayType.setBackground(getResources().getDrawable(R.drawable.bg_day_type_blue));
}
} else {
tvDayType.setVisibility(View.GONE);
}
if (jsonObject.optJSONArray("list") != null && jsonObject.optJSONArray("list").length() >= 0) {
viewPoint.setVisibility(View.VISIBLE);
} else {
viewPoint.setVisibility(View.INVISIBLE);
}
} else {
tvDayType.setVisibility(View.INVISIBLE);
viewPoint.setVisibility(View.INVISIBLE);
}
dayView.setText(day.getText());
chinaDay.setText(day.getChinaDate());
if (day.getDate().getYear() == mManager.getCurrentMonthDate().getYear()
&& day.getDate().getMonthOfYear() == mManager.getCurrentMonthDate().getMonthOfYear()
|| mManager.getState() == State.WEEK) {
//如果日期是当前月份
if (i > 4) {
//周末
dayView.setTextColor(getResources().getColor(R.color.cal_blue_dark));
chinaDay.setTextColor(getResources().getColor(R.color.cal_blue_dark));
} else {
//非周末
dayView.setTextColor(getResources().getColor(R.color.cal_text_normal));
chinaDay.setTextColor(getResources().getColor(R.color.cal_text_normal));
}
} else {
//日期不是当前月份
if (i > 4) {
//周末
dayView.setTextColor(getResources().getColor(R.color.cal_blue_light));
chinaDay.setTextColor(getResources().getColor(R.color.cal_blue_light));
} else {
//非周末
dayView.setTextColor(getResources().getColor(R.color.cal_line_grey));
chinaDay.setTextColor(getResources().getColor(R.color.cal_line_grey));
}
}
layout.setSelected(day.isSelected());
if (day.getDate().equals(mManager.getToday()) && day.isSelected()) {
//日期对象是今天,并且被选中
if (day.getDate().getYear() == mManager.getCurrentMonthDate().getYear()
&& day.getDate().getMonthOfYear() == mManager.getCurrentMonthDate().getMonthOfYear()) {
//如果日期是当前月份
if (i > 4) {
//周末
dayView.setTextColor(getResources().getColorStateList(R.color.text_calendar_week));
chinaDay.setTextColor(getResources().getColorStateList(R.color.text_calendar_week));
} else {
//非周末
dayView.setTextColor(getResources().getColorStateList(R.color.text_calendar));
chinaDay.setTextColor(getResources().getColorStateList(R.color.text_calendar));
}
} else {
//日期不是当前月份
if (i > 4) {
//周末
dayView.setTextColor(getResources().getColorStateList(R.color.text_calendar_week_out_month));
chinaDay.setTextColor(getResources().getColorStateList(R.color.text_calendar_week_out_month));
} else {
//非周末
dayView.setTextColor(getResources().getColorStateList(R.color.text_calendar_out_month));
chinaDay.setTextColor(getResources().getColorStateList(R.color.text_calendar_out_month));
}
}
layout.setBackground(getResources().getDrawable(R.drawable.bg_btn_calendar_today_selected));
viewPoint.setBackground(getResources().getDrawable(R.drawable.bg_calendar_point_white));
layout.setSelected(true);
} else if (day.getDate().equals(mManager.getToday())) {
//日期对象今天
viewPoint.setBackground(getResources().getDrawable(R.drawable.bg_calendar_point_blue));
layout.setBackground(getResources().getDrawable(R.drawable.bg_btn_calendar_today));
layout.setSelected(true);
} else {
//日期对象被选中
viewPoint.setBackground(getResources().getDrawable(R.drawable.bg_calendar_point_blue));
layout.setBackground(getResources().getDrawable(R.drawable.bg_btn_calendar));
}
dayView.setCurrent(day.isCurrent());
boolean enables = day.isEnabled();
dayView.setEnabled(enables);
if (enables) { // 解除点击限制,所有的都可以点击
layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
LocalDate date = day.getDate();
if (mManager.getState() == State.MONTH) {
//判断当前视图状态为月份视图
if (date.getYear() > mManager.getCurrentMonthDate().getYear()) {
//选中日期年份大于当前显示年份
next();
} else if (date.getYear() < mManager.getCurrentMonthDate().getYear()) {
//选中日期年份小于当前显示年份
prev();
} else {
//选中日期年份等于当前显示年份
if (date.getMonthOfYear() > mManager.getCurrentMonthDate().getMonthOfYear()) {
//选中月份大于当前月份
next();
} else if (date.getMonthOfYear() < mManager.getCurrentMonthDate().getMonthOfYear()) {
//选中月份小于当前月份
prev();
}
}
}
if (mManager.selectDay(date)) {
populateLayout();
if (mListener != null) {
//执行选中回调
mListener.onDateSelected(date);
}
}
}
});
} else {
dayView.setOnClickListener(null);
}
}
}
/**
* 翻转到前一页
*/
public void prev(){
if (mManager.prev()) {
populateLayout();
}
if (mListener != null) {
//执行选中回调
mListener.onDateSelected(mManager.getSelectedDay());
}
this.setAnimation(left_in);
left_in.start();
}
/**
* 翻转到下一页
*/
public void next(){
if (mManager.next()) {
populateLayout();
}
if (mListener != null) {
//执行选中回调
mListener.onDateSelected(mManager.getSelectedDay());
}
this.setAnimation(right_in);
right_in.start();
}
public LinearLayout getWeeksView() {
return mWeeksView;
}
private WeekView getWeekView(int index) {
int cnt = mWeeksView.getChildCount();
if(cnt < index + 1) {
for (int i = cnt; i < index + 1; i++) {
View view = getView();
mWeeksView.addView(view);
}
}
return (WeekView) mWeeksView.getChildAt(index);
}
private View getView() {
View view = mRecycleBin.recycleView();
if (view == null) {
view = mInflater.inflate(R.layout.week_layout, this, false);
} else {
view.setVisibility(View.VISIBLE);
}
return view;
}
private void cacheView(int index) {
View view = mWeeksView.getChildAt(index);
if(view != null) {
mWeeksView.removeViewAt(index);
mRecycleBin.addView(view);
}
}
public LocalDate getSelectedDate() {
return mManager.getSelectedDay();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mResizeManager.recycle();
}
private class RecycleBin {
private final Queue<View> mViews = new LinkedList<View>();
public View recycleView() {
return mViews.poll();
}
public void addView(View view) {
mViews.add(view);
}
}
public interface OnDateSelect {
public void onDateSelected(LocalDate date);
}
}
MainActivity主界面
基本的事件处理以及监听器的使用
package com.eroad.widget.calendar;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.joda.time.LocalDate;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
import com.eroad.widget.calendar.CollapseCalendarView.OnDateSelect;
import com.eroad.widget.calendar.CollapseCalendarView.OnTitleClickListener;
import com.eroad.widget.calendar.manager.CalendarManager;
import com.eroad.widget.calendar.manager.CalendarManager.OnMonthChangeListener;
import com.example.calendarnew.R;
/**
* Main
* @author MaJian
*
*/
public class MainActivity extends Activity {
private CollapseCalendarView calendarView;
private CalendarManager mManager;
private JSONObject json;
private SimpleDateFormat sdf;
private boolean show = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sdf = new SimpleDateFormat("yyyy-MM-dd");
calendarView = (CollapseCalendarView) findViewById(R.id.calendar);
mManager = new CalendarManager(LocalDate.now(),
CalendarManager.State.MONTH, LocalDate.now().withYear(100),
LocalDate.now().plusYears(100));
//月份切换监听器
mManager.setMonthChangeListener(new OnMonthChangeListener() {
@Override
public void monthChange(String month, LocalDate mSelected) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, month, Toast.LENGTH_SHORT).show();
}
});
/**
* 日期选中监听器
*/
calendarView.setDateSelectListener(new OnDateSelect() {
@Override
public void onDateSelected(LocalDate date) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, date.toString(), Toast.LENGTH_SHORT).show();
}
});
calendarView.setTitleClickListener(new OnTitleClickListener() {
@Override
public void onTitleClick() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "点击标题", Toast.LENGTH_SHORT).show();
}
});
//回到今天
findViewById(R.id.btn_today).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
calendarView.changeDate(LocalDate.now().toString());
}
});
//周月切换
findViewById(R.id.btn_changemode).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mManager.toggleView();
calendarView.populateLayout();
}
});
//显示或者隐藏农历
findViewById(R.id.btn_hide).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
calendarView.showChinaDay(show);
show = !show;
}
});
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 9);
cal.set(Calendar.DAY_OF_MONTH, 0);
json = new JSONObject();
try {
for (int i = 0; i < 30; i++) {
JSONObject jsonObject2 = new JSONObject();
if (i <= 6) {
jsonObject2.put("type", "休");
} else if ( i > 6 && i< 11) {
jsonObject2.put("type", "班");
}
if (i%3 == 0) {
jsonObject2.put("list", new JSONArray());
}
json.put(sdf.format(cal.getTime()), jsonObject2);
cal.add(Calendar.DAY_OF_MONTH, 1);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
//设置数据显示
calendarView.setArrayData(json);
//初始化日历管理器
calendarView.init(mManager);
}
}
布局文件源码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.eroad.widget.calendar.CollapseCalendarView
android:id="@+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.eroad.widget.calendar.CollapseCalendarView>
<Button
android:id="@+id/btn_today"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="回到今天" />
<Button
android:id="@+id/btn_changemode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="周月切换" />
<Button
android:id="@+id/btn_hide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="隐藏、显示农历" />
</LinearLayout>
下面给大家分享下效果图
如果大家比较满意可以下载完整版demo
链接:http://download.csdn.net/detail/voidmain_123/9275921