公司项目需要一个功能全面的日历,然后就在网上找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


版权声明:本文为voidmain_123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/voidmain_123/article/details/49885877