Android定制日历,支持周月切换,日期标记,农历显示,节假日
公司项目需要一个功能全面的日历,然后就在网上找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;}@Overridepublic 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")@Overrideprotected 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);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { return mResizeManager.onInterceptTouchEvent(ev);}@Overridepublic 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(); }}@Overrideprotected 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 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 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();}@Overrideprotected void onDetachedFromWindow() { super.onDetachedFromWindow(); mResizeManager.recycle();}private class RecycleBin { private final Queue mViews = new LinkedList(); 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;@Overrideprotected 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
更多相关文章
- android studio删除module
- Android(安卓)"java.lang.NoClassDefFoundError:*"报错的处理方
- android 点击EditText 弹出日期选择器DatePickerDialog
- andrioid——checkbox勾选按钮自定义样式
- Android——使用DatePicker和TimePicker显示当前日期和时间
- Android根据当前时间获取前面的时间日期,或者之后的时间日期
- Android(安卓)RadioGroup和RadioButton案例及详解
- 最简便实现Android(安卓)ListView选中item高亮显示
- Android(安卓)studio 常用快捷键记录