Merge pull request ' 添加日历的控制类和视图类并在MainActivity中调用' (#10) from p86231950/ShowMe:master into master

pull/11/head
p28679143 4 years ago
commit 67117366ba

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="16" />
<bytecodeTargetLevel target="11" />
</component>
</project>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

@ -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'

@ -1,6 +1,5 @@
package com.idealist.calendarview;
public class CalendarAttr {
static int RecTop;

@ -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);
}
}

@ -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<CalendarPager> {
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;
}
}

@ -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<CalendarDay>
*/
public static List<CalendarDay> generateItemForMonthView(int year, int month) {
List<CalendarDay> 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<CalendarDay> generateItemForWeekView(int year, int month, int day) {
List<CalendarDay> 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<CalendarDay> 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() {
//返回值为booleantrue说明滚动尚未完成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);
}
}

@ -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<CalendarDay> 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<CalendarDay> getItems() {
return items;
}
public void setItems(List<CalendarDay> 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);
}
}

@ -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<CalendarView> 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<CalendarView> 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) {
}
}

@ -0,0 +1,7 @@
package com.idealist.calendarview.interf;
import com.idealist.calendarview.CalendarDay;
public interface OnSelectDateListener {
void onSelectOtherMonth(int offset);//点击其它月份日期
}

@ -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() + "");
}
}

@ -1,18 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/CLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:layout_height="match_parent">
<TextView
<LinearLayout
android:id="@+id/custom_date_view"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/custom_year_view"
android:layout_width="72sp"
android:layout_marginLeft="30dp"
android:layout_height="match_parent"
android:textColor="#ff25adff"
android:textSize="27sp" />
<TextView
android:id="@+id/custom_month_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom"
android:textColor="#26ADFF"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:orientation="horizontal">
<TextView
style="@style/weekIndicatorStyle"
android:text="日"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="一"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="二"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="三"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="四"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="五"/>
<TextView
style="@style/weekIndicatorStyle"
android:text="六"/>
</LinearLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/cdLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.idealist.calendarview.CalendarPager
android:id="@+id/custom_vp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!-- <androidx.recyclerview.widget.RecyclerView-->
<!-- android:id="@+id/list_item"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- app:layout_behavior="com.idealist.calendarview.RecyclerViewBehavior"/>-->
<!-- <cc.trity.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/add_schedule"-->
<!-- android:layout_width="40dp"-->
<!-- android:layout_height="40dp"-->
<!-- android:layout_gravity="bottom|start"-->
<!-- app:fab_size="mini"-->
<!-- app:fab_title="FAB 0"-->
<!-- app:fab_colorNormal="#e41c1c"-->
<!-- app:fab_icon="@drawable/schedule"-->
<!-- />-->
<!-- <cc.trity.floatingactionbutton.FloatingActionsMenu-->
<!-- android:id="@+id/right_labels"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="bottom|end"-->
<!-- app:fab_expandDirection="up"-->
<!-- app:fab_colorNormal="#f0f01a"-->
<!-- app:fab_icon = "@drawable/ic_baseline_add_24"-->
<!-- app:fab_addButtonSize="mini"-->
<!-- >-->
<!-- <cc.trity.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/diary_entry"-->
<!-- android:layout_width="30dp"-->
<!-- android:layout_height="30dp"-->
<!-- android:background="@drawable/ic_baseline_add_24"-->
<!-- app:fab_size="normal"-->
<!-- app:fab_title="FAB 3"-->
<!-- app:fab_colorNormal="#09F7F7"-->
<!-- app:fab_icon="@drawable/diary"-->
<!-- />-->
<!-- <cc.trity.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/course_entry"-->
<!-- android:layout_width="50dp"-->
<!-- android:layout_height="50dp"-->
<!-- app:fab_colorNormal="#24d63c"-->
<!-- app:fab_size="normal"-->
<!-- app:fab_icon="@drawable/course"-->
<!-- />-->
<!-- <cc.trity.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/zone_entry"-->
<!-- android:layout_width="50dp"-->
<!-- android:layout_height="50dp"-->
<!-- app:fab_colorNormal="#501161"-->
<!-- app:fab_size="normal"-->
<!-- app:fab_icon="@drawable/zone"-->
<!-- />-->
<!-- </cc.trity.floatingactionbutton.FloatingActionsMenu>-->
<!-- <com.google.android.material.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/addSchedule"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="end|bottom"-->
<!-- android:layout_margin="30dp"-->
<!-- android:backgroundTint="#7575EF"-->
<!-- android:src="@drawable/ic_baseline_add_24"-->
<!-- android:contentDescription="@string/add"-->
<!-- app:fabSize="normal"-->
<!-- />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="weekIndicatorStyle">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center</item>
<item name="android:textSize">13sp</item>
<item name="android:textColor">#ff25adff</item>
</style>
<style name="VideoShareImageView">
<item name="android:layout_height">25dp</item>
<item name="android:layout_width">25dp</item>
<item name="android:layout_marginTop">8dp</item>
</style>
</resources>
Loading…
Cancel
Save