package com.loonggg.weekcalendar.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.ViewFlipper; import com.loonggg.weekcalendar.R; import com.loonggg.weekcalendar.base.SimpleBaseAdapter; import com.loonggg.weekcalendar.entity.CalendarData; import com.loonggg.weekcalendar.utils.WeekCalendarUtil; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; public class WeekCalendar extends LinearLayout { RelativeLayout mIvPrevious; TextView mTvYearMouth; RelativeLayout mIvNext; RelativeLayout month_layout; ViewFlipper mRvDay; ImageView preBtn, nextBtn; private Context context; private GridView mGridView = null; private OnDateClickListener listener; private List<CalendarData> calendarDatas; private Map<Integer, List> weeks; private int weekPosition;//星期在月份中的位置 private CalendarData today; private CalendarData theDayOfSelected;//被选中的日期 private CalendarData theDayForShow;//用于展示数据的中间变量 private int daysSelectedTextColor, todayTextColor, weekTextColor, weekBackgroundColor, monthBackgroundColor, monthTextColor, daysTextColor; private boolean hideTodayName = false, isCornerMark = false, isShowMonth = true; private float daysTextSize, weekTextSize; private Drawable daysSelectedBackground, nextArrowBg, preArrowBg, cornerMarkBg; private List<String> selectDateList = null; private OnCurrentMonthDateListener onCurrentMonthDateListener; public WeekCalendar(Context context) { super(context); init(context, null); } public WeekCalendar(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } /** * 初始化View */ private void init(Context context, AttributeSet attrs) { this.context = context; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.view_calender, this, true); mIvPrevious = (RelativeLayout) findViewById(R.id.iv_previous); preBtn = (ImageView) findViewById(R.id.pre_btn); nextBtn = (ImageView) findViewById(R.id.next_btn); mTvYearMouth = (TextView) findViewById(R.id.tv_year_mouth); month_layout = (RelativeLayout) findViewById(R.id.month_layout); mIvNext = (RelativeLayout) findViewById(R.id.iv_next); mRvDay = (ViewFlipper) findViewById(R.id.rv_day); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WeekCalendar); daysSelectedTextColor = typedArray.getColor(R.styleable .WeekCalendar_daysSelectedTextColor, Color.WHITE); todayTextColor = typedArray.getColor(R.styleable .WeekCalendar_todayTextColor, Color.GRAY); weekTextColor = typedArray.getColor(R.styleable .WeekCalendar_weekTextColor, Color.GRAY); weekBackgroundColor = typedArray.getColor(R.styleable .WeekCalendar_weekBackgroundColor, Color.WHITE); monthBackgroundColor = typedArray.getColor(R.styleable.WeekCalendar_monthBackgroundColor, Color.LTGRAY); monthTextColor = typedArray.getColor(R.styleable.WeekCalendar_monthTextColor, Color.WHITE); daysTextColor = typedArray.getColor(R.styleable.WeekCalendar_daysTextColor, Color.GRAY); nextArrowBg = typedArray.getDrawable(R.styleable.WeekCalendar_nextArrowBg); preArrowBg = typedArray.getDrawable(R.styleable.WeekCalendar_preArrowBg); daysSelectedBackground = typedArray.getDrawable(R.styleable.WeekCalendar_daysSelectedBackground); cornerMarkBg = typedArray.getDrawable(R.styleable.WeekCalendar_cornerMarkBg); hideTodayName = typedArray.getBoolean(R.styleable.WeekCalendar_hideTodayName, false); isCornerMark = typedArray.getBoolean(R.styleable.WeekCalendar_isCornerMark, false); daysTextSize = typedArray.getDimension(R.styleable.WeekCalendar_daysTextSize, 16f); weekTextSize = typedArray.getDimension(R.styleable.WeekCalendar_weekTextSize, 16f); isShowMonth = typedArray.getBoolean(R.styleable.WeekCalendar_isShowMonth, true); initDatas(); initView(); typedArray.recycle(); } /** * 初始化数据 */ private void initDatas() { calendarDatas = new ArrayList<>(); getToday();//获取当天的数据 theDayOfSelected = today; theDayForShow = today; getWholeMonthDatas(theDayOfSelected); weekPosition = WeekCalendarUtil.getTheWeekPosition(weeks, theDayOfSelected); } /** * 设置整个月的数据 */ private void getWholeMonthDatas(CalendarData data) { calendarDatas = WeekCalendarUtil.getWholeMonthDay(data);//获取某天所在的整个月的数据(包含用于显示的上个月的天数和下个月的天数) weeks = WeekCalendarUtil.getWholeWeeks(calendarDatas);//获取当月有几个星期,以及每一星期对应的数据星期数据 if (onCurrentMonthDateListener != null) { onCurrentMonthDateListener.onCallbackMonthDate(String.valueOf(data.year), String.valueOf(data.month)); } mTvYearMouth.setText(String.format("%s年%s月", String.valueOf(data.year), String.valueOf(data.month))); } /** * 初始化月控件 */ private void initView() { if (isShowMonth) { month_layout.setVisibility(View.VISIBLE); } else { month_layout.setVisibility(View.GONE); } if (nextArrowBg != null) { nextBtn.setBackgroundDrawable(nextArrowBg); } if (preArrowBg != null) { preBtn.setBackgroundDrawable(preArrowBg); } month_layout.setBackgroundColor(monthBackgroundColor); mTvYearMouth.setTextColor(monthTextColor); mIvPrevious.setOnClickListener(new OnClickListener() {//跳到上一个月 @Override public void onClick(View v) { showLastView(false);//显示上一个星期/月 } }); mIvNext.setOnClickListener(new OnClickListener() {//跳到下一个月 @Override public void onClick(View v) { showNextView(false);//显示下一个星期/月 } }); mGridView = addDayView(); mGridView.setAdapter(new CalendarAdapter(context, weeks.get(weekPosition))); mRvDay.addView(mGridView, 0); } /** * 初始化日期 */ private GridView addDayView() { LayoutParams params = new LayoutParams( AbsListView.LayoutParams.FILL_PARENT, AbsListView.LayoutParams.WRAP_CONTENT); final GridView gridView = new GridView(context); gridView.setNumColumns(7); gridView.setGravity(Gravity.CENTER_VERTICAL); gridView.setSelector(new ColorDrawable(Color.TRANSPARENT)); gridView.setVerticalSpacing(1); gridView.setHorizontalSpacing(1); gridView.setLayoutParams(params); return gridView; } public void setSelectDates(List<String> list) { selectDateList = list; } /** * 获取今天的参数 */ private void getToday() { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d"); String currentDate = sdf.format(date); int year = Integer.parseInt(currentDate.split("-")[0]); int month = Integer.parseInt(currentDate.split("-")[1]); int day = Integer.parseInt(currentDate.split("-")[2]); today = new CalendarData(year, month, day); } private float mLastX = -1; /** * scrollview的ontouchEvent和其他的ViewGroup的方法还是很大不同, 该方法一般和ontouchEvent 一起用 * onInterceptTouchEvent()主要功能是控制触摸事件的分发,例如是子视图的点击事件还是滑动事件。 */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mLastX = event.getRawX(); break; case MotionEvent.ACTION_MOVE: float dx = mLastX - event.getRawX(); //X移动坐标 if (dx > 80) { // 向左滑 showNextView(true);//显示下一个星期/月 return true; } else if (dx < -80) { showLastView(true);//显示上一个星期/月 return true; } break; } return super.onInterceptTouchEvent(event); } /** * 显示下一个星期/月的数据 */ public void showNextView(boolean isShowNextWeek) { GridView mGridView = addDayView(); mGridView.setAdapter(new CalendarAdapter(context, getNextWeekDatas(isShowNextWeek))); mRvDay.addView(mGridView, 1); mRvDay.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_left_in)); mRvDay.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_left_out)); mRvDay.showNext(); mRvDay.removeViewAt(0); } /** * 显示上一个星期/月的数据 */ public void showLastView(boolean isShowLastWeek) { GridView mGridView = addDayView(); mGridView.setAdapter(new CalendarAdapter(context, getLastWeekDatas(isShowLastWeek))); mRvDay.addView(mGridView, 1); mRvDay.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_right_in)); mRvDay.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_right_out)); mRvDay.showNext(); mRvDay.removeViewAt(0); } /** * 获取下个星期的数据 * * @param isShowNextWeek true 获取下各星期的数据,如果false 直接获取下各月第一个星期的数据 * @return */ public List<CalendarData> getNextWeekDatas(boolean isShowNextWeek) { if (weekPosition == weeks.size() - 1 || !isShowNextWeek) {//最后一个星期,加载下一个月的数据,或者直接获取下个月 theDayForShow = (theDayForShow.isNextMonthDay) ? theDayForShow : WeekCalendarUtil.getTheDayOfNextMonth(theDayForShow); getWholeMonthDatas(theDayForShow); // 为了让数据连贯,直接跳到第二个星期,这里可能没有数据交叉的情况,不跳到第二个星期 判断这个月的第一天是否是星期天 weekPosition = (WeekCalendarUtil.getWeekdayOfFirstDayInMonth(theDayForShow) == 0 || !isShowNextWeek) ? 0 : 1; } else { weekPosition++; } return (List<CalendarData>) weeks.get(weekPosition); } public List<CalendarData> getLastWeekDatas(boolean isShowLastWeek) { if (weekPosition == 0 || !isShowLastWeek) {//第一个星期,加载上一个月的数据,或者直接获取上个月 theDayForShow = (theDayForShow.isLastMonthDay) ? theDayForShow : WeekCalendarUtil.getTheDayOfLastMonth(theDayForShow); getWholeMonthDatas(theDayForShow); if (isShowLastWeek) { // 为了让数据连贯,直接跳到倒数第二个星期,这里可能没有数据交叉的情况,不跳倒数到第二个星期,判断这个月的最后是否是星期六 weekPosition = weeks.size() - ((WeekCalendarUtil.getWeekdayOfEndDayInMonth(theDayForShow) == 6) ? 1 : 2); } else {//直接获取上个月 weekPosition = 0; } } else { weekPosition--; } return (List<CalendarData>) weeks.get(weekPosition); } /** * 日期列表适配器 */ public class CalendarAdapter extends SimpleBaseAdapter { List<CalendarData> datas; public CalendarAdapter(Context context, List<CalendarData> datas) { super(context, datas); this.datas = datas; } @Override public int getItemResource() { return R.layout.item_calendar; } @Override public View getItemView(final int position, View convertView, final ViewHolder viewHolder) { final CalendarData calendar = (CalendarData) getItem(position); final TextView dayView = (TextView) viewHolder.getView(R.id.tv_calendar_day); final TextView weekView = (TextView) viewHolder.getView(R.id.tv_calendar_week); ImageView corner_mark_iv = (ImageView) viewHolder.getView(R.id.corner_mark_iv); weekView.setText(WeekCalendarUtil.getWeekString(mContext).get(position)); dayView.setTextSize(daysTextSize); weekView.setTextSize(weekTextSize); weekView.setBackgroundColor(weekBackgroundColor); if (isCornerMark) { corner_mark_iv.setBackgroundDrawable(cornerMarkBg); } else { corner_mark_iv.setVisibility(View.GONE); } if (!hideTodayName) { if (!calendar.isSameDay(today)) { dayView.setText(String.valueOf(calendar.day)); } else { dayView.setText(String.valueOf("今")); } } else { dayView.setText(String.valueOf(calendar.day)); } if (calendar.isSameDay(theDayOfSelected)) {//被选中的日期是白的 dayView.setTextColor(daysSelectedTextColor); dayView.setBackgroundDrawable(daysSelectedBackground); } else if (calendar.isLastMonthDay || calendar.isNextMonthDay) {//上一个月、下一个月的日期是灰色的 dayView.setTextColor(Color.LTGRAY); dayView.setBackgroundDrawable(null); } else if (calendar.isSameDay(today)) {//当天的日期是橘黄色的 dayView.setTextColor(todayTextColor); dayView.setText("今"); dayView.setBackgroundDrawable(null); } else { dayView.setBackgroundDrawable(null); dayView.setTextColor(weekTextColor); } if (selectDateList != null) { for (int i = 0; i < selectDateList.size(); i++) { String dateStr = selectDateList.get(i); String[] dates = dateStr.split("-"); CalendarData cd = new CalendarData(); cd.year = Integer.parseInt(dates[0]); cd.month = Integer.parseInt(dates[1]); cd.day = Integer.parseInt(dates[2]); if (calendar.isSameDay(cd)) { corner_mark_iv.setVisibility(View.VISIBLE); break; } else { corner_mark_iv.setVisibility(View.GONE); } } } //如果设置了回调,则设置点击事件 dayView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { theDayOfSelected = datas.get(position); theDayForShow = datas.get(position); notifyDataSetChanged(); if (listener != null) { listener.onDateClick(getTheDayOfSelected()); } } }); return convertView; } } /** * 点击选中日期的回调接口 */ public interface OnDateClickListener { void onDateClick(String time); } /** * 回调当前显示的年月 */ public interface OnCurrentMonthDateListener { void onCallbackMonthDate(String year, String month); } /** * 设置显示当前月份的回调接口方法 * * @param onCurrentMonthDateListener */ public void setOnCurrentMonthDateListener(OnCurrentMonthDateListener onCurrentMonthDateListener) { this.onCurrentMonthDateListener = onCurrentMonthDateListener; } /** * 设置回调接口 */ public void setOnDateClickListener(OnDateClickListener listener) { this.listener = listener; } /** * 获取被选中日期的日期字符串 * * @return */ private String getTheDayOfSelected() { if (theDayOfSelected != null) { String sYear = String.valueOf(theDayOfSelected.year); String sMonth = String.valueOf(theDayOfSelected.month); String sDay = String.valueOf(theDayOfSelected.day); return String.format("%s-%s-%s", sYear, (2 > sMonth.length()) ? "0" + sMonth : "" + sMonth, (2 > sDay.length()) ? "0" + sDay : "" + sDay); } return ""; } /** * 判断当前选中日期是否是今天 * * @return */ public boolean isTodayIsSelectedDay() { return today.isSameDay(theDayForShow) && today.isSameDay(theDayOfSelected); } /** * 判断显示的是否是今天,如果不是,跳转到今天 * * @return 是否是今天 */ public boolean showToday() { if (!isTodayIsSelectedDay() || weekPosition != WeekCalendarUtil.getTheWeekPosition(weeks, today)) {//如果显示的不是当天 int mode = 0;//动画模式(0 没有动画,1 向左动 , 2 向右动) if (theDayForShow.year > today.year || theDayForShow.month > today.month) {//下一个月 getWholeMonthDatas(today); weekPosition = WeekCalendarUtil.getTheWeekPosition(weeks, today); mode = 2; } else if (theDayForShow.year < today.year || theDayForShow.month < today.month) {//上一个月 getWholeMonthDatas(today); weekPosition = WeekCalendarUtil.getTheWeekPosition(weeks, today); mode = 1; } else {//本月 int position = WeekCalendarUtil.getTheWeekPosition(weeks, today); if (weekPosition < position) {//上个星期 mode = 1; } else if (weekPosition > position) {//下个星期 mode = 2; } weekPosition = position; } theDayOfSelected = today; theDayForShow = today; GridView mGridView = addDayView(); mGridView.setAdapter(new CalendarAdapter(context, weeks.get(weekPosition))); mRvDay.addView(mGridView, 1); if (mode == 2) { mRvDay.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_right_in)); mRvDay.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_right_out)); } else if (mode == 1) { mRvDay.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_left_in)); mRvDay.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_left_out)); } else { mRvDay.setInAnimation(null); mRvDay.setOutAnimation(null); } mRvDay.showNext(); mRvDay.removeViewAt(0); return false; } return true; } }