diff --git a/src/.idea/compiler.xml b/src/.idea/compiler.xml
index 659bf43..fb7f4a8 100644
--- a/src/.idea/compiler.xml
+++ b/src/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/src/.idea/misc.xml b/src/.idea/misc.xml
index df8860d..860da66 100644
--- a/src/.idea/misc.xml
+++ b/src/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/src/CalendarView/build.gradle b/src/CalendarView/build.gradle
index 8bc4f08..e92336c 100644
--- a/src/CalendarView/build.gradle
+++ b/src/CalendarView/build.gradle
@@ -32,6 +32,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
+ implementation project(path: ':DataBase')
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarAttr.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarAttr.java
index d38df74..f8f9e04 100644
--- a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarAttr.java
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarAttr.java
@@ -1,6 +1,5 @@
package com.idealist.calendarview;
-
public class CalendarAttr {
static int RecTop;
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPager.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPager.java
new file mode 100644
index 0000000..7e8d41a
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPager.java
@@ -0,0 +1,152 @@
+package com.idealist.calendarview;
+
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+@CoordinatorLayout.DefaultBehavior(CalendarPagerBehavior.class)
+public class CalendarPager extends ViewPager {
+
+ private CalendarAttr attr;
+
+ private OnPageChangeListener mOnPageChangeListener;
+
+ public static int CURRENT_DAY_INDEX = 1000;
+
+ private int mCurrPosition = CURRENT_DAY_INDEX;
+
+ private int pageScrollState = ViewPager.SCROLL_STATE_IDLE;
+
+ public CalendarPager(Context context) {
+ super(context, null);
+ }
+
+ public CalendarPager(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ initPager();
+ }
+
+ private void initPager() {
+ ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ mCurrPosition = position;
+ if (mOnPageChangeListener != null) {
+ CalendarViewAdapter adapter = (CalendarViewAdapter) getAdapter();
+ assert adapter != null;
+ adapter.updateViewByScrollHorizontally(position);
+ mOnPageChangeListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ pageScrollState = state;
+ }
+ };
+ addOnPageChangeListener(pageChangeListener);
+ }
+
+ public void setAttr(CalendarAttr attr) {
+ this.attr = attr;
+ }
+
+ @Override
+ public void setAdapter(@Nullable PagerAdapter adapter) {
+ super.setAdapter(adapter);
+ setCurrentItem(1000);
+ mCurrPosition = 1000;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (attr != null && attr.getCalendarType() == State.VIEW_FULL) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+ int height = 0xffffff;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ child.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ int h = child.getMeasuredHeight();
+ height = Math.min(h, height);
+ }
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ public void setmOnPageChangeListener(OnPageChangeListener mOnPageChangeListener) {
+ this.mOnPageChangeListener = mOnPageChangeListener;
+ }
+
+ public void selectOtherMonth(int offset) {
+ CalendarViewAdapter adapter = (CalendarViewAdapter) getAdapter();
+ adapter.saveSelectedDate();
+ adapter.updateDayInViewState(mCurrPosition + offset);
+ setCurrentItem(mCurrPosition + offset);
+ }
+
+ public int getViewHeight() {
+ return attr.getViewHeight();
+ }
+
+ public int getItemHeight() {
+ return attr.getItemHeight();
+ }
+
+ public int getScrollLevel() {
+ return attr.getScrollLevel();
+ }
+
+ public void setScrollLevel(int scrollLevel) {
+ attr.setScrollLevel(scrollLevel);
+ }
+
+ public int getPageScrollState() {
+ return pageScrollState;
+ }
+
+ public void setPageScrollState(int pageScrollState) {
+ this.pageScrollState = pageScrollState;
+ }
+
+ public CalendarAttr getAttr() {
+ return attr;
+ }
+
+ public int getmCurrPosition() {
+ return mCurrPosition;
+ }
+
+ /**
+ * 月视图到周视图可向上滑动距离距离
+ *a
+ * @return 距离
+ */
+ public int getTopMovableDistance() {
+ CalendarViewAdapter adapter = (CalendarViewAdapter) getAdapter();
+ assert adapter != null;
+ return attr.getItemHeight() * (CalendarUtils.getWeekOfMonth(adapter.getSelectDay()) - 1);
+ }
+
+ public interface OnPageChangeListener {
+ void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
+
+ void onPageSelected(int position);
+
+ void onPageScrollStateChanged(int state);
+ }
+}
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPagerBehavior.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPagerBehavior.java
new file mode 100644
index 0000000..7c3525c
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarPagerBehavior.java
@@ -0,0 +1,182 @@
+package com.idealist.calendarview;
+
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.recyclerview.widget.RecyclerView;
+
+import static android.content.ContentValues.TAG;
+
+public class CalendarPagerBehavior extends CoordinatorLayout.Behavior {
+ private int mTop = 0;
+ private int touchSlop = 1;
+
+ @Override
+ public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull CalendarPager child, @NonNull View dependency) {
+ return dependency instanceof RecyclerView;
+ }
+
+ @Override
+ public boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull CalendarPager child, int layoutDirection) {
+ parent.onLayoutChild(child, layoutDirection);
+ child.offsetTopAndBottom(mTop);
+ return true;
+ }
+
+ private int confirm = 0;
+ private float downX, downY, lastY, lastTop;
+ private boolean isVerticalScroll;
+ private boolean directionUpa;
+
+ @Override
+ public boolean onTouchEvent(@NonNull CoordinatorLayout parent, @NonNull CalendarPager child, @NonNull MotionEvent ev) {
+ if (downY > lastTop) {
+ return false;
+ }
+ Log.i(TAG, "onTouchEvent: onTouchEvent");
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (isVerticalScroll) {
+ directionUpa = ev.getY() < lastY;
+ if (child.getScrollLevel() == State.LEVEL_TOP) {
+ CalendarAttr.setRecTop(State.DEFAULT_ITEM_HEIGHT + (int) (ev.getY() - downY));
+ CalendarUtils.scroll(parent.getChildAt(1), (int) (lastY - ev.getY()),
+ State.DEFAULT_ITEM_HEIGHT, State.DEFAULT_ITEM_HEIGHT * 6);
+ } else if (child.getScrollLevel() == State.LEVEL_MEDIUM) {
+ CalendarAttr.setRecTop(State.DEFAULT_ITEM_HEIGHT * 6 + (int) (ev.getY() - downY));
+ if (directionUpa) {
+ CalendarUtils.scroll(parent.getChildAt(1), (int) (lastY - ev.getY()),
+ State.DEFAULT_ITEM_HEIGHT, State.DEFAULT_ITEM_HEIGHT * 6);
+ } else {
+ CalendarUtils.scroll(parent.getChildAt(1), (int) (lastY - ev.getY()),
+ State.DEFAULT_ITEM_HEIGHT * 6, State.DEFAULT_ITEM_HEIGHT_FULL * 6);
+ }
+ } else {
+ CalendarAttr.setRecTop(child.getViewHeight() + (int) (ev.getY() - downY));
+ CalendarUtils.scroll(parent.getChildAt(1), (int) (lastY - ev.getY()),
+ State.DEFAULT_ITEM_HEIGHT * 6, State.DEFAULT_ITEM_HEIGHT_FULL * 6);
+ }
+ lastY = ev.getY();
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (isVerticalScroll) {
+ CalendarViewAdapter adapter = (CalendarViewAdapter) child.getAdapter();
+ if (adapter != null) {
+ if (directionUpa) {
+ if (adapter.getCalendarType() == State.VIEW_MONTH) {
+ child.setScrollLevel(State.LEVEL_TOP);
+ adapter.changeCalendarType(State.VIEW_WEEK);
+ CalendarUtils.scrollTo(parent, (RecyclerView) parent.getChildAt(1),
+ State.DEFAULT_ITEM_HEIGHT, 300);
+ } else if (adapter.getCalendarType() == State.VIEW_FULL) {
+ child.setScrollLevel(State.LEVEL_MEDIUM);
+ adapter.changeCalendarType(State.VIEW_MONTH);
+ CalendarUtils.scrollTo(parent, (RecyclerView) parent.getChildAt(1),
+ State.DEFAULT_ITEM_HEIGHT * 6, 300);
+ }
+ } else {
+ if (adapter.getCalendarType() == State.VIEW_WEEK) {
+ child.setScrollLevel(State.LEVEL_MEDIUM);
+ adapter.changeCalendarType(State.VIEW_MONTH);
+ CalendarUtils.scrollTo(parent, (RecyclerView) parent.getChildAt(1),
+ State.DEFAULT_ITEM_HEIGHT * 6, 300);
+ } else if (adapter.getCalendarType() == State.VIEW_MONTH) {
+ child.setScrollLevel(State.LEVEL_BOTTOM);
+ adapter.changeCalendarType(State.VIEW_FULL);
+ CalendarUtils.scrollTo(parent, (RecyclerView) parent.getChildAt(1),
+ State.DEFAULT_ITEM_HEIGHT_FULL * 6, 300);
+ }
+ }
+ }
+ isVerticalScroll = false;
+ return true;
+ }
+ break;
+ }
+ isVerticalScroll = false;
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull CalendarPager child, @NonNull MotionEvent ev) {
+ Log.i(TAG, "onInterceptTouchEvent: Try to intercept!" + isVerticalScroll);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ downX = ev.getX();
+ downY = ev.getY();
+ lastTop = CalendarAttr.getRecTop();
+ lastY = downY;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (downY > lastTop) {
+ return false;
+ }
+ if (Math.abs(ev.getY() - downY) > 25 && Math.abs(ev.getX() - downX) <= 25 && !isVerticalScroll) {
+ isVerticalScroll = true;
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (isVerticalScroll) {
+ isVerticalScroll = false;
+ return true;
+ }
+ break;
+ }
+ return isVerticalScroll;
+ }
+
+ private int dependencyViewTop = -1;
+
+ @Override
+ public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull CalendarPager child, @NonNull View dependency) {
+ Log.i(TAG, "onDependentViewChanged: !");
+ CalendarViewAdapter adapter = (CalendarViewAdapter) child.getAdapter();
+
+ if (dependencyViewTop != -1) {
+ int dy = dependency.getTop() - dependencyViewTop;
+ int top = child.getTop();
+
+ if (dy > touchSlop) {
+ assert adapter != null;
+ adapter.changeCalendarType(State.VIEW_MONTH);
+ } else if (dy < -touchSlop) {
+ assert adapter != null;
+ adapter.changeCalendarType(State.VIEW_WEEK);
+ }
+
+ if (dy > -top)
+ dy = -top;
+
+ if (dy < -top - child.getTopMovableDistance()) {
+ dy = -top - child.getTopMovableDistance();
+ }
+
+ child.offsetTopAndBottom(dy);
+// adapter.changeCalendarType(State.VIEW_WEEK);
+ }
+
+ if (dependencyViewTop > child.getItemHeight() - 24
+ && dependencyViewTop < child.getItemHeight() + 24
+ && mTop > -touchSlop - child.getTopMovableDistance()
+ && mTop < touchSlop - child.getTopMovableDistance()) {
+ child.setScrollLevel(State.LEVEL_TOP);
+ adapter.changeCalendarType(State.VIEW_WEEK);
+ }
+ if (dependencyViewTop > child.getViewHeight() - 24
+ && dependencyViewTop < child.getViewHeight() + 24
+ && mTop < touchSlop
+ && mTop > -touchSlop) {
+ child.setScrollLevel(State.LEVEL_MEDIUM);
+ adapter.changeCalendarType(State.VIEW_MONTH);
+ }
+ return true;
+ }
+}
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarUtils.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarUtils.java
new file mode 100644
index 0000000..338e02b
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarUtils.java
@@ -0,0 +1,363 @@
+package com.idealist.calendarview;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.Scroller;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.Cursor;
+
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.showme.database.utils.ScheduleSQLUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+import static android.content.ContentValues.TAG;
+
+public class CalendarUtils {
+
+
+ /**
+ * 判断某年是否是闰年
+ *
+ * @param year year
+ * @return 是否是闰年
+ */
+ public static boolean isLeapYear(int year) {
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+ }
+
+ /**
+ * 获取某个月份的天数
+ *
+ * @param year 年
+ * @param month 月
+ * @return 对应月份天数
+ */
+ public static int getDayNumOfMonth(int year, int month) {
+ int res = 31;
+ switch (month) {
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ res = 30;
+ break;
+ case 2:
+ if (isLeapYear(year))
+ res = 29;
+ else
+ res = 28;
+ break;
+ default:
+ break;
+ }
+ return res;
+ }
+
+ /**
+ * 获得某年某月某天为星期几
+ * 0 - 6 日 - 六
+ *
+ * @param year 年
+ * @param month 月
+ * @return 星期
+ */
+ private static int getDayOfWeek(int year, int month, int day) {
+ Calendar date = Calendar.getInstance();
+ date.set(year, month - 1, day, 12, 0);
+ return date.get(Calendar.DAY_OF_WEEK) - 1;
+ }
+
+ /**
+ * 为月视图生成 Items
+ *
+ * @param year year
+ * @param month month
+ * @return List
+ */
+ public static List generateItemForMonthView(int year, int month) {
+ List dates = new ArrayList<>();
+
+ CalendarDay currDay = getCurrDay();
+ int daysNumOfMonth = getDayNumOfMonth(year, month);
+ int preDiff = getDayOfWeek(year, month, 1);
+
+ int preYear = year;
+ int nextYear = year;
+ int preMonth = month - 1;
+ int nextMonth = month + 1;
+
+ if (month == 1) {
+ preYear = year - 1;
+ preMonth = 12;
+ } else if (month == 12) {
+ nextYear = year + 1;
+ nextMonth = 1;
+ }
+
+ int dayIndex = 1;
+ for (int i = 1; i <= 42; ++i) {
+ CalendarDay date = new CalendarDay();
+ if (i <= preDiff) {
+ date.setYear(preYear);
+ date.setMonth(preMonth);
+ date.setDay(getDayNumOfMonth(preYear, preMonth) - preDiff + i);
+ date.setMonthState(State.DAY_PAST_MONTH);
+ } else if (i > preDiff + daysNumOfMonth) {
+ date.setYear(nextYear);
+ date.setMonth(nextMonth);
+ date.setDay(dayIndex++);
+ date.setMonthState(State.DAY_NEXT_MONTH);
+ } else {
+ date.setYear(year);
+ date.setMonth(month);
+ date.setDay(i - preDiff);
+ date.setMonthState(State.DAY_CURR_MONTH);
+ date.setCurrDay(date.equals(currDay));
+ }
+ dates.add(date);
+ if (date.equals(CalendarViewAdapter.loadSelectedDate())) {
+ date.setSelectState(State.DAY_SELECT);
+ }
+// if (ScheduleSQLUtils.isScheduleMarked(date.toString())) {
+// date.setMarkSchedule(true);
+// }
+ }
+ return dates;
+ }
+
+ /**
+ * 为周视图生成 Items
+ *
+ * @param year int 年
+ * @param month int 月
+ * @param day int 天
+ * @return List Items
+ */
+ public static List generateItemForWeekView(int year, int month, int day) {
+ List dates = new ArrayList<>();
+ CalendarDay currDay = getCurrDay();
+ int dayOfWeekOfCurr = getDayOfWeek(year, month, day);
+ int dayNumOfCurrMonth = getDayNumOfMonth(year, month);
+
+ int setYear = year;
+ int setMonth = month;
+ if (day - dayOfWeekOfCurr <= 0) {
+ setMonth = month - 1;
+ if (month == 1) {
+ setYear = year - 1;
+ setMonth = 12;
+ }
+ } else if (day + (6 - dayOfWeekOfCurr) > dayNumOfCurrMonth) {
+ setMonth = month + 1;
+ if (month == 12) {
+ setYear = year + 1;
+ setMonth = 1;
+ }
+ }
+
+ for (int i = 0; i < 7; ++i) {
+ CalendarDay date = new CalendarDay();
+
+ if (day - dayOfWeekOfCurr + i <= 0) {
+ date.setYear(setYear);
+ date.setMonth(setMonth);
+ date.setDay(day - dayOfWeekOfCurr + i + getDayNumOfMonth(setYear, setMonth));
+ date.setMonthState(State.DAY_PAST_MONTH);
+ } else if (day - dayOfWeekOfCurr + i > dayNumOfCurrMonth) {
+ date.setYear(setYear);
+ date.setMonth(setMonth);
+ date.setDay(day - dayOfWeekOfCurr + i - dayNumOfCurrMonth);
+ date.setMonthState(State.DAY_NEXT_MONTH);
+ } else {
+ date.setYear(year);
+ date.setMonth(month);
+ date.setDay(day - dayOfWeekOfCurr + i);
+ date.setMonthState(State.DAY_CURR_MONTH);
+ date.setCurrDay(date.equals(currDay));
+ }
+ dates.add(date);
+ if (date.equals(CalendarViewAdapter.loadSelectedDate())) {
+ date.setSelectState(State.DAY_SELECT);
+ }
+ if (ScheduleSQLUtils.isScheduleMarked(date.toString())) {
+ date.setMarkSchedule(true);
+ }
+ }
+ return dates;
+ }
+
+
+ /**
+ * 获得当前日期
+ *
+ * @return 日期
+ */
+ public static CalendarDay getCurrDay() {
+ CalendarDay day = new CalendarDay();
+ Calendar date = Calendar.getInstance();
+ day.setDay(date.get(Calendar.DATE));
+ day.setMonth(date.get(Calendar.MONTH) + 1);
+ day.setYear(date.get(Calendar.YEAR));
+ day.setCurrDay(true);
+// Log.e("util", day.toString());
+ return day;
+ }
+
+ /**
+ * 获得对应日期周视图前后的周视图日历项
+ *
+ * @param day CalendarDay 当前日历项
+ * @param offset int 前后周视图选项 -1为前一周 1为后一周
+ * @return CalendarDay 日历项
+ */
+ public static CalendarDay getNearWeekDay(CalendarDay day, int offset) {
+ Calendar date = Calendar.getInstance();
+ CalendarDay resDay = new CalendarDay();
+ date.set(day.getYear(), day.getMonth() - 1, day.getDay(), 12, 0);
+ date.add(Calendar.DATE, offset * 7);
+ resDay.setYear(date.get(Calendar.YEAR));
+ resDay.setMonth(date.get(Calendar.MONTH) + 1);
+ resDay.setDay(date.get(Calendar.DATE));
+ return resDay;
+ }
+
+ /**
+ * 返回对应日历项月的上或下一月日历项
+ *
+ * @param day CalendarDay
+ * @param offset 前后月视图选项 -1为前一月 1为后一月
+ * @return CalendarDay
+ */
+ public static CalendarDay getNearMonthDay(CalendarDay day, int offset) {
+ if (offset == 0)
+ return day;
+ Calendar date = Calendar.getInstance();
+ CalendarDay resDay = new CalendarDay();
+ date.set(day.getYear(), day.getMonth() - 1, day.getDay(), 12, 0);
+ date.add(Calendar.MONTH, offset);
+ resDay.setYear(date.get(Calendar.YEAR));
+ resDay.setMonth(date.get(Calendar.MONTH) + 1);
+ resDay.setDay(date.get(Calendar.DATE));
+ return resDay;
+ }
+
+ public static int getIndexOfCurrDay(int CalendarType) {
+ List items;
+ CalendarDay day = getCurrDay();
+ if (CalendarType == State.VIEW_MONTH || CalendarType == State.VIEW_FULL) {
+ items = generateItemForMonthView(day.getYear(), day.getMonth());
+ } else {
+ items = generateItemForWeekView(day.getYear(), day.getMonth(), day.getDay());
+ }
+ return items.indexOf(day);
+ }
+
+ /**
+ * 获得 day 所在周是其所在月的第几周
+ *
+ * @param day CalendarDay
+ * @return int
+ */
+ public static int getWeekOfMonth(CalendarDay day) {
+ Calendar date = Calendar.getInstance();
+ date.set(day.getYear(), day.getMonth(), day.getDay(), 12, 0);
+ return date.get(Calendar.WEEK_OF_MONTH);
+ }
+
+
+ /**
+ * 删除方法, 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理
+ *
+ * @param child 需要移动的View
+ * @param dy 实际偏移量
+ * @param minOffset 最小偏移量
+ * @param maxOffset 最大偏移量
+ * @return void
+ */
+ public static int scroll(View child, int dy, int minOffset, int maxOffset) {
+ Log.i(TAG, "scroll: scrolling in viewTools");
+ final int initOffset = child.getTop();
+ int offset = calcOffset(initOffset - dy, minOffset, maxOffset) - initOffset;
+ child.offsetTopAndBottom(offset);
+ return -offset;
+ }
+
+ /**
+ * 计算偏移距离
+ *
+ * @param offset 偏移值
+ * @param min 最小偏移值
+ * @param max 最大偏移值
+ * @return int offset
+ */
+ private static int calcOffset(int offset, int min, int max) {
+ if (offset > max) {
+ return max;
+ } else return Math.max(offset, min);
+ }
+
+ /**
+ * 通过scrollTo方法完成协调布局的滑动,其中主要使用了ViewCompat.postOnAnimation
+ *
+ * @param parent 协调布局parent
+ * @param child 协调布局协调滑动的child
+ * @param y 滑动目标位置y轴数值
+ * @param duration 滑动执行时间
+ */
+ public static void scrollTo(final CoordinatorLayout parent, final RecyclerView child, final int y, int duration) {
+ final Scroller scroller = new Scroller(parent.getContext());
+ int top = CalendarAttr.getRecTop();
+ scroller.startScroll(0, top, 0, y - top, duration); //设置scroller的滚动偏移量
+ ViewCompat.postOnAnimation(child, new Runnable() {
+ @Override
+ public void run() {
+ //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。
+ // 这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。
+ if (scroller.computeScrollOffset()) {
+ int delta = scroller.getCurrY() - child.getTop();
+ child.offsetTopAndBottom(delta);
+ CalendarAttr.setRecTop(child.getTop());
+ parent.dispatchDependentViewsChanged(child);
+ ViewCompat.postOnAnimation(child, this);
+ }
+ }
+ });
+ }
+
+ /**
+ * 得到TouchSlop
+ *
+ * @param context 上下文
+ * @return int touchSlop的具体值
+ */
+ public static int getTouchSlop(Context context) {
+ return ViewConfiguration.get(context).getScaledTouchSlop();
+ }
+
+ public static void forceStopRecyclerViewScroll(RecyclerView mRecyclerView) {
+ mRecyclerView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0));
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ public static String getTimeForZone() {
+ Calendar date = Calendar.getInstance();
+ SimpleDateFormat sdf = new SimpleDateFormat();
+ sdf.applyPattern("MM-dd HH:mm:ss a");
+ Date time = date.getTime();
+ return sdf.format(time);
+ }
+}
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarView.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarView.java
new file mode 100644
index 0000000..9ec68ca
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarView.java
@@ -0,0 +1,272 @@
+package com.idealist.calendarview;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.idealist.calendarview.interf.OnSelectDateListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CalendarView extends View implements View.OnLongClickListener {
+
+ private CalendarViewAdapter adapter;
+
+ private CalendarAttr attr;
+
+ private int mItemHeight;
+
+ private int mItemWidth;
+
+ private int mViewHeight;
+
+ private int mBaseLine;
+
+ private boolean isClick;
+
+ private boolean isScroll;
+
+ private int mTextSize;
+
+ private int mCurrItem;
+
+ private int mRowCount;
+
+ MotionEvent event;
+
+ /**
+ * 点击坐标
+ */
+ private float mX, mY;
+
+ private List items = new ArrayList<>();
+
+ private CalendarDay seedDay;
+
+ private OnSelectDateListener onSelectDateListener;
+
+ private OnCalendarClickListener clickListener;
+
+ public CalendarView(Context context,
+ CalendarAttr attr,
+ CalendarViewAdapter adapter,
+ OnSelectDateListener onSelectDateListener,
+ OnCalendarClickListener clickListener) {
+ super(context);
+ this.attr = attr;
+ this.adapter = adapter;
+ this.clickListener = clickListener;
+ this.onSelectDateListener = onSelectDateListener;
+ this.setOnLongClickListener(this);
+ initView();
+ }
+
+ /**
+ * 初始化 View
+ */
+ private void initView() {
+ mRowCount = attr.getRowCount();
+ mViewHeight = attr.getViewHeight();
+ mItemHeight = attr.getItemHeight();
+ mTextSize = attr.getTextSize();
+ mBaseLine = (int) (mTextSize + mItemHeight) / 2;
+ mCurrItem = CalendarUtils.getIndexOfCurrDay(State.VIEW_MONTH);
+ }
+
+
+ /**
+ * 为对应视图生成对应日历项, 以SeedDay为对应
+ */
+ final int generateItem() {
+ if (attr.getCalendarType() != State.VIEW_WEEK)
+ items = CalendarUtils.generateItemForMonthView(seedDay.getYear(), seedDay.getMonth());
+ else
+ items = CalendarUtils.generateItemForWeekView(seedDay.getYear(), seedDay.getMonth(), seedDay.getDay());
+ return items.indexOf(seedDay);
+ }
+
+ /**
+ * 当视图变化时变化 UI
+ */
+ public void changeViewType() {
+ if (attr.getCalendarType() == State.VIEW_FULL) {
+ attr.setItemHeight(State.DEFAULT_ITEM_HEIGHT_FULL);
+ } else {
+ attr.setItemHeight(State.DEFAULT_ITEM_HEIGHT);
+ }
+ mItemHeight = attr.getItemHeight();
+ mViewHeight = attr.getViewHeight();
+ setViewHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+ mCurrItem = generateItem();
+ invalidate();
+ }
+
+ public void updateView() {
+ mCurrItem = generateItem();
+ invalidate();
+ }
+
+
+ public CalendarDay getSeedDay() {
+ return seedDay;
+ }
+
+ public void setSeedDay(CalendarDay seedDay) {
+ this.seedDay = seedDay;
+ }
+
+
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (attr.getCalendarType() != State.VIEW_FULL) {
+ setMeasuredDimension(widthMeasureSpec, mViewHeight);
+ }
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ float touchX = event.getX();
+ float touchY = event.getY();
+ int action = event.getAction();
+ float disX, disY;
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mX = touchX;
+ mY = touchY;
+ isClick = true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ disX = touchX - mX;
+ disY = touchY - mY;
+ if (Math.abs(disX) > 2 * mItemWidth || Math.abs(disY) > 2 * mItemHeight) {
+ isScroll = true;
+ }
+ isClick = false;
+ break;
+ case MotionEvent.ACTION_UP:
+ if (isClick) {
+ items.get(mCurrItem).setSelectState(State.DAY_UN_SELECT);
+ mCurrItem = getIndexOnView();
+ adapter.setSelectDay(items.get(mCurrItem));
+ if (items.get(mCurrItem).getMonthState() != State.DAY_CURR_MONTH) {
+ items.get(mCurrItem).setSelectState(State.DAY_UN_SELECT);
+ onSelectDateListener.onSelectOtherMonth(items.get(mCurrItem).getMonthState());
+ mCurrItem = 0;
+ } else {
+ items.get(mCurrItem).setSelectState(State.DAY_SELECT);
+ }
+ if (adapter.getSelectDay().isMarkSchedule()) {
+ clickListener.OnClick(adapter.getSelectDay());
+ }
+ invalidate();
+ }
+ break;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ public void setItems(List items) {
+ this.items = items;
+ }
+
+ public void setmCurrItem(int mCurrItem) {
+ this.mCurrItem = mCurrItem;
+ }
+
+ private int getIndexOnView() {
+ int indexX = (int) mX / mItemWidth;
+ int indexY = (int) mY / mItemHeight;
+ int position = -1;
+ if (isClick) {
+ if (indexX > 6) indexX = 6;
+ position = 7 * indexY + indexX;
+ }
+ if (position > 41)
+ position = 41;
+ return position;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mItemWidth = getWidth() / 7;
+ mItemHeight = attr.getItemHeight();
+ mRowCount = attr.getRowCount();
+ mBaseLine = (int) (mTextSize * 1.5);
+ int sW = mItemWidth / 2;
+ int sH = mBaseLine;
+ for (int i = 0; i < mRowCount; ++i) {
+ for (int j = 0; j < 7; ++j) {
+ draw(canvas, items.get(7 * i + j), sW + mItemWidth * j, sH + mItemHeight * i);
+ }
+ }
+ }
+
+ private void draw(Canvas canvas, CalendarDay day, int x, int y) {
+ onDrawText(canvas, day, x, y);
+ onDrawMark(canvas, day, x, y);
+ }
+
+ private void onDrawText(Canvas canvas, CalendarDay day, int x, int y) {
+ Paint paint = new Paint();
+ paint.setTextSize(mTextSize);
+ paint.setColor(Color.GRAY);
+ paint.setTextAlign(Paint.Align.CENTER);
+// Log.e("View", day.toString());
+ if (day.isCurrDay()) {
+ paint.setColor(Color.BLUE);
+ } else if (day.getSelectState() == State.DAY_SELECT) {
+ paint.setColor(Color.GREEN);
+ } else if (day.getMonthState() == State.DAY_CURR_MONTH) {
+ paint.setColor(Color.BLACK);
+ }
+ canvas.drawText(Integer.toString(day.getDay()), x, y, paint);
+ }
+
+ private void onDrawMark(Canvas canvas, CalendarDay day, int x, int y) {
+ if (day.isMarkSchedule()) {
+ Paint paint = new Paint();
+ paint.setColor(Color.BLUE);
+ canvas.drawCircle(x, y+20, 10, paint);
+ }
+ }
+
+
+ /**
+ * 设置 View 高度
+ *
+ * @param height 高度
+ */
+ private void setViewHeight(int height) {
+ Log.e(null, "setViewHeight");
+ ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) this.getLayoutParams();
+ params.height = height;
+ this.setLayoutParams(params);
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ if (clickListener != null) {
+ clickListener.OnLongClick(adapter.getSelectDay());
+ }
+ return false;
+ }
+
+ public interface OnCalendarClickListener {
+ void OnClick(CalendarDay day);
+ void OnLongClick(CalendarDay day);
+ }
+}
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarViewAdapter.java b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarViewAdapter.java
new file mode 100644
index 0000000..2629e7e
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/CalendarViewAdapter.java
@@ -0,0 +1,188 @@
+package com.idealist.calendarview;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.viewpager.widget.PagerAdapter;
+
+import com.idealist.calendarview.interf.OnSelectDateListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CalendarViewAdapter extends PagerAdapter {
+
+ private CalendarAttr attr;
+ private List mViews = new ArrayList<>();
+ private int mCurrPosition = CalendarPager.CURRENT_DAY_INDEX;
+
+ // 保存上一次点击的日期
+ private static CalendarDay mRecDate;
+ private CalendarDay mSelectDay;
+ private OnCalendarTypeChangeListener typeChangeListener;
+
+ public CalendarViewAdapter(Context context, CalendarAttr attr,
+ OnSelectDateListener dateListener,
+ CalendarView.OnCalendarClickListener longClickListener) {
+ super();
+ this.attr = attr;
+ initViewAdapter(context, dateListener, longClickListener);
+ }
+
+
+ private void initViewAdapter(Context context, OnSelectDateListener dateListener,
+ CalendarView.OnCalendarClickListener longClickListener) {
+ mSelectDay = CalendarUtils.getCurrDay();
+ CalendarDay day;
+ for (int i = 0; i < 3; i++) {
+ CalendarView view = new CalendarView(context, attr, this, dateListener, longClickListener);
+ day = CalendarUtils.getNearMonthDay(mSelectDay, i - 1);
+ view.setSeedDay(day);
+ mViews.add(view);
+ }
+ }
+
+ /**
+ * 通过滑动更新 View
+ *
+ * @param position 需要更新的 View 的 position
+ */
+ public void updateViewByScrollHorizontally(int position) {
+ Log.e("adapter", "position: " + position + " mCurrPosition: " + mCurrPosition);
+ CalendarDay seedDay = mViews.get(position % 3).getSeedDay();
+ int offset = 0;
+ if (position > mCurrPosition) {
+ offset = 1;
+ } else if (position < mCurrPosition) {
+ offset = -1;
+ }
+ CalendarView view = mViews.get((position + offset) % 3);
+ //TODO 注意视图
+ if (attr.getCalendarType() != State.VIEW_WEEK)
+ view.setSeedDay(CalendarUtils.getNearMonthDay(seedDay, offset));
+ else
+ view.setSeedDay(CalendarUtils.getNearWeekDay(seedDay, offset));
+ }
+
+
+ public int getCalendarType() {
+ return attr.getCalendarType();
+ }
+
+ /**
+ * 当视图类型改变时更新 View 的显示模式
+ *
+ * @param updateType 更新的显示模式
+ */
+ public void changeCalendarType(int updateType) {
+ attr.setCalendarType(updateType);
+ CalendarDay seedDay = mViews.get(mCurrPosition % 3).getSeedDay();
+ saveSelectedDate();
+ for (int i = -1; i < 2; ++i) {
+ CalendarView view = mViews.get((mCurrPosition + i) % 3);
+ if (updateType == State.VIEW_WEEK) {
+ view.setSeedDay(CalendarUtils.getNearWeekDay(mSelectDay, i));
+ } else {
+ view.setSeedDay(CalendarUtils.getNearMonthDay(mSelectDay, i));
+ }
+ view.changeViewType();
+ }
+ }
+
+// /**
+// * 由 pager 通知 adapter 发生点击事件更改,进行处理
+// * @param day 选中 CalendarDay
+// */
+// public void notifyDataChanged() {
+//
+// }
+
+ public void saveSelectedDate() {
+ mRecDate = mSelectDay;
+ }
+
+ public static CalendarDay loadSelectedDate() {
+ return mRecDate;
+ }
+
+ @Override
+ public int getCount() {
+ // 实现无限循环
+ return Integer.MAX_VALUE;
+ }
+
+
+ @Override
+ public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+ super.setPrimaryItem(container, position % 3, object);
+ this.mCurrPosition = position;
+ Log.e("adapterPri", Integer.toString(position));
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+// if (position < 2) return null;
+
+ CalendarView view = mViews.get(position % 3);
+ view.generateItem();
+ view.invalidate();
+
+ int mChildNum = container.getChildCount();
+ if (mChildNum == mViews.size()) {
+ container.removeView(view);
+ }
+
+ if (container.getChildCount() < mViews.size()) {
+ container.addView(view, 0);
+ } else {
+ container.addView(view, position % 3);
+ }
+ return view;
+ }
+
+ public void updateDayInViewState(int position) {
+ CalendarView view = mViews.get(position % 3);
+ view.setSeedDay(mSelectDay);
+ view.updateView();
+ }
+
+ public void updateViewScheduleChange() {
+ CalendarView view = mViews.get(mCurrPosition % 3);
+ view.updateView();
+ }
+
+ public void setTypeChangeListener(OnCalendarTypeChangeListener typeChangeListener) {
+ this.typeChangeListener = typeChangeListener;
+ }
+
+
+ public CalendarDay getSelectDay() {
+ return mSelectDay;
+ }
+
+ public void setSelectDay(CalendarDay mSelectDay) {
+ this.mSelectDay = mSelectDay;
+ }
+
+ public List getViews() {
+ return mViews;
+ }
+
+ public interface OnCalendarTypeChangeListener {
+ void onCalendarTypeChanged(int Calendar_Type);
+ }
+
+ @Override
+ public boolean isViewFromObject(@NonNull android.view.View view, @NonNull Object object) {
+ return view == ((View) object);
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+
+ }
+}
diff --git a/src/CalendarView/src/main/java/com/idealist/calendarview/interf/OnSelectDateListener.java b/src/CalendarView/src/main/java/com/idealist/calendarview/interf/OnSelectDateListener.java
new file mode 100644
index 0000000..79c5829
--- /dev/null
+++ b/src/CalendarView/src/main/java/com/idealist/calendarview/interf/OnSelectDateListener.java
@@ -0,0 +1,7 @@
+package com.idealist.calendarview.interf;
+
+import com.idealist.calendarview.CalendarDay;
+
+public interface OnSelectDateListener {
+ void onSelectOtherMonth(int offset);//点击其它月份日期
+}
diff --git a/src/app/src/main/java/com/showme/myapplication/MainActivity.java b/src/app/src/main/java/com/showme/myapplication/MainActivity.java
index 92bd10a..8df5d92 100644
--- a/src/app/src/main/java/com/showme/myapplication/MainActivity.java
+++ b/src/app/src/main/java/com/showme/myapplication/MainActivity.java
@@ -2,13 +2,114 @@ package com.showme.myapplication;
import androidx.appcompat.app.AppCompatActivity;
+import android.annotation.SuppressLint;
import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.widget.TextView;
+
+import com.idealist.calendarview.CalendarAttr;
+import com.idealist.calendarview.CalendarDay;
+import com.idealist.calendarview.CalendarPager;
+import com.idealist.calendarview.CalendarUtils;
+import com.idealist.calendarview.CalendarView;
+import com.idealist.calendarview.CalendarViewAdapter;
+import com.idealist.calendarview.State;
+import com.idealist.calendarview.interf.OnSelectDateListener;
+
+import java.util.TimeZone;
public class MainActivity extends AppCompatActivity {
+ private TextView tvMonth;
+ private TextView tvYear;
+
+ private CalendarDay currentDay;
+
+ private CalendarView currentView;
+
+ private CalendarPager pager;
+
+ private CalendarViewAdapter viewAdapter;
+
+ private CalendarAttr attr;
+
+ private OnSelectDateListener onSelectDateListener;
+
+ private CalendarView.OnCalendarClickListener clickListener;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+ DisplayMetrics dm = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getRealMetrics(dm);
+ int height = dm.heightPixels;
+ State.setDefaultItemHeightFull((height - 42 - 3*State.DEFAULT_ITEM_HEIGHT) / 6);
+
+ initCalendar();
+
+ attr = new CalendarAttr();
+ attr.setCalendarType(State.VIEW_MONTH);
+ attr.setScrollLevel(State.LEVEL_MEDIUM);
+
+ initListener();
+ viewAdapter = new CalendarViewAdapter(this, attr, onSelectDateListener,
+ clickListener);
+ initPager();
}
+
+ private void initCalendar() {
+ tvMonth = findViewById(R.id.custom_month_view);
+ tvYear = findViewById(R.id.custom_year_view);
+ currentDay = CalendarUtils.getCurrDay();
+ updateCalendar();
+ }
+
+ private void initPager() {
+ pager = findViewById(R.id.custom_vp);
+ pager.setAttr(attr);
+ pager.setAdapter(viewAdapter);
+
+ pager.setmOnPageChangeListener(new CalendarPager.OnPageChangeListener() {
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ currentView = viewAdapter.getViews().get(position % 3);
+ currentDay = currentView.getSeedDay();
+ updateCalendar();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ }
+ });
+ }
+
+ private void initListener() {
+ onSelectDateListener = offset -> pager.selectOtherMonth(offset);
+ clickListener = new CalendarView.OnCalendarClickListener() {
+ @Override
+ public void OnClick(CalendarDay day) {
+// updateSchedule(day);
+ }
+
+ @Override
+ public void OnLongClick(CalendarDay day) {
+
+ }
+ };
+ }
+
+ @SuppressLint("SetTextI18n")
+ private void updateCalendar() {
+ tvMonth.setText(currentDay.getMonth() + "");
+ tvYear.setText(currentDay.getYear() + "");
+ }
+
}
\ No newline at end of file
diff --git a/src/app/src/main/res/layout/activity_main.xml b/src/app/src/main/res/layout/activity_main.xml
index 4fc2444..6bc8ba7 100644
--- a/src/app/src/main/res/layout/activity_main.xml
+++ b/src/app/src/main/res/layout/activity_main.xml
@@ -1,18 +1,142 @@
-
+ android:layout_height="match_parent">
-
+
+
+
+
+
+
+
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/app/src/main/res/values/styles.xml b/src/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..8a2b97e
--- /dev/null
+++ b/src/app/src/main/res/values/styles.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file