Commit 335d6fe5 by zhengnw@sobot.com

widget 1.1.1 日历控件 可以选区间,也可以单选,自定义

parent 99e2ef44
...@@ -13,7 +13,7 @@ ext { ...@@ -13,7 +13,7 @@ ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名 PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'widget' //项目名 PUBLISH_ARTIFACT_ID = 'widget' //项目名
// PUBLISH_ARTIFACT_ID = 'widget_x' //项目名 // PUBLISH_ARTIFACT_ID = 'widget_x' //项目名
PUBLISH_VERSION = '1.1.0' //版本号 PUBLISH_VERSION = '1.1.1' //版本号
} }
......
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
/**
* 月视图基础控件,可自由继承实现
* 可通过此扩展各种视图如:MonthView、RangeMonthView、MultiMonthView
*/
public abstract class BaseMonthView extends BaseView {
MonthViewPager mMonthViewPager;
/**
* 当前日历卡年份
*/
protected int mYear;
/**
* 当前日历卡月份
*/
protected int mMonth;
/**
* 日历的行数
*/
protected int mLineCount;
/**
* 日历高度
*/
protected int mHeight;
/**
* 下个月偏移的数量
*/
protected int mNextDiff;
public BaseMonthView(Context context) {
super(context);
}
/**
* 初始化日期
*
* @param year year
* @param month month
*/
final void initMonthWithDate(int year, int month) {
mYear = year;
mMonth = month;
initCalendar();
mHeight = CalendarUtil.getMonthViewHeight(year, month, mItemHeight, mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
}
/**
* 初始化日历
*/
@SuppressLint("WrongConstant")
private void initCalendar() {
mNextDiff = CalendarUtil.getMonthEndDiff(mYear, mMonth, mDelegate.getWeekStart());
int preDiff = CalendarUtil.getMonthViewStartDiff(mYear, mMonth, mDelegate.getWeekStart());
int monthDayCount = CalendarUtil.getMonthDaysCount(mYear, mMonth);
mItems = CalendarUtil.initCalendarForMonthView(mYear, mMonth, mDelegate.getCurrentDay(), mDelegate.getWeekStart());
if (mItems.contains(mDelegate.getCurrentDay())) {
mCurrentItem = mItems.indexOf(mDelegate.getCurrentDay());
} else {
mCurrentItem = mItems.indexOf(mDelegate.mSelectedCalendar);
}
if (mCurrentItem > 0 &&
mDelegate.mCalendarInterceptListener != null &&
mDelegate.mCalendarInterceptListener.onCalendarIntercept(mDelegate.mSelectedCalendar)) {
mCurrentItem = -1;
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {
mLineCount = 6;
} else {
mLineCount = (preDiff + monthDayCount + mNextDiff) / 7;
}
addSchemesFromMap();
invalidate();
}
/**
* 获取点击选中的日期
*
* @return return
*/
protected Calendar getIndex() {
if (mItemWidth == 0 || mItemHeight == 0) {
return null;
}
if (mX <= mDelegate.getCalendarPaddingLeft() || mX >= getWidth() - mDelegate.getCalendarPaddingRight()) {
onClickCalendarPadding();
return null;
}
int indexX = (int) (mX - mDelegate.getCalendarPaddingLeft()) / mItemWidth;
if (indexX >= 7) {
indexX = 6;
}
int indexY = (int) mY / mItemHeight;
int position = indexY * 7 + indexX;// 选择项
if (position >= 0 && position < mItems.size()) {
return mItems.get(position);
}
return null;
}
private void onClickCalendarPadding() {
if (mDelegate.mClickCalendarPaddingListener == null) {
return;
}
Calendar calendar = null;
int indexX = (int) (mX - mDelegate.getCalendarPaddingLeft()) / mItemWidth;
if (indexX >= 7) {
indexX = 6;
}
int indexY = (int) mY / mItemHeight;
int position = indexY * 7 + indexX;// 选择项
if (position >= 0 && position < mItems.size()) {
calendar = mItems.get(position);
}
if (calendar == null) {
return;
}
mDelegate.mClickCalendarPaddingListener.onClickCalendarPadding(mX, mY, true, calendar,
getClickCalendarPaddingObject(mX, mY, calendar));
}
/**
* 获取点击事件处的对象
*
* @param x x
* @param y y
* @param adjacentCalendar adjacent calendar
* @return obj can as null
*/
@SuppressWarnings("unused")
protected Object getClickCalendarPaddingObject(float x, float y, Calendar adjacentCalendar) {
return null;
}
/**
* 记录已经选择的日期
*
* @param calendar calendar
*/
final void setSelectedCalendar(Calendar calendar) {
mCurrentItem = mItems.indexOf(calendar);
}
/**
* 更新显示模式
*/
final void updateShowMode() {
mLineCount = CalendarUtil.getMonthViewLineCount(mYear, mMonth,
mDelegate.getWeekStart(), mDelegate.getMonthViewShowMode());
mHeight = CalendarUtil.getMonthViewHeight(mYear, mMonth, mItemHeight, mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
invalidate();
}
/**
* 更新周起始
*/
final void updateWeekStart() {
initCalendar();
mHeight = CalendarUtil.getMonthViewHeight(mYear, mMonth, mItemHeight, mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
}
@Override
void updateItemHeight() {
super.updateItemHeight();
mHeight = CalendarUtil.getMonthViewHeight(mYear, mMonth, mItemHeight, mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
}
@Override
void updateCurrentDate() {
if (mItems == null)
return;
if (mItems.contains(mDelegate.getCurrentDay())) {
for (Calendar a : mItems) {//添加操作
a.setCurrentDay(false);
}
int index = mItems.indexOf(mDelegate.getCurrentDay());
mItems.get(index).setCurrentDay(true);
}
invalidate();
}
/**
* 获取选中的下标
*
* @param calendar calendar
* @return 获取选中的下标
*/
protected final int getSelectedIndex(Calendar calendar) {
return mItems.indexOf(calendar);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mLineCount != 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 开始绘制前的钩子,这里做一些初始化的操作,每次绘制只调用一次,性能高效
* 没有需要可忽略不实现
* 例如:
* 1、需要绘制圆形标记事件背景,可以在这里计算半径
* 2、绘制矩形选中效果,也可以在这里计算矩形宽和高
*/
protected void onPreviewHook() {
// TODO: 2017/11/16
}
/**
* 循环绘制开始的回调,不需要可忽略
* 绘制每个日历项的循环,用来计算baseLine、圆心坐标等都可以在这里实现
*
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
protected void onLoopStart(int x, int y) {
// TODO: 2017/11/16
}
@Override
protected void onDestroy() {
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* 基本的适配器
*/
abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter {
@SuppressWarnings("all")
LayoutInflater mInflater;
private List<T> mItems;
private OnItemClickListener onItemClickListener;
private OnClickListener onClickListener;
Context mContext;
BaseRecyclerAdapter(Context context) {
mContext = context;
this.mItems = new ArrayList<>();
mInflater = LayoutInflater.from(context);
onClickListener = new OnClickListener() {
@Override
public void onClick(int position, long itemId) {
if (onItemClickListener != null)
onItemClickListener.onItemClick(position, itemId);
}
};
}
@SuppressWarnings("ConstantConditions")
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerView.ViewHolder holder = onCreateDefaultViewHolder(parent, viewType);
if (holder != null) {
holder.itemView.setTag(holder);
holder.itemView.setOnClickListener(onClickListener);
}
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
onBindViewHolder(holder, mItems.get(position), position);
}
abstract RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type);
abstract void onBindViewHolder(RecyclerView.ViewHolder holder, T item, int position);
@Override
public int getItemCount() {
return mItems.size();
}
void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@SuppressWarnings("unused")
void addAll(List<T> items) {
if (items != null && items.size() > 0) {
mItems.addAll(items);
notifyItemRangeInserted(mItems.size(), items.size());
}
}
final void addItem(T item) {
if (item != null) {
this.mItems.add(item);
notifyItemChanged(mItems.size());
}
}
@SuppressWarnings("unused")
final List<T> getItems() {
return mItems;
}
final T getItem(int position) {
if (position < 0 || position >= mItems.size())
return null;
return mItems.get(position);
}
static abstract class OnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag();
onClick(holder.getAdapterPosition(), holder.getItemId());
}
public abstract void onClick(int position, long itemId);
}
interface OnItemClickListener {
void onItemClick(int position, long itemId);
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.List;
/**
* 基本的日历View,派生出MonthView 和 WeekView
*/
public abstract class BaseView extends View implements View.OnClickListener, View.OnLongClickListener {
CalendarViewDelegate mDelegate;
/**
* 当前月份日期的笔
*/
protected Paint mCurMonthTextPaint = new Paint();
/**
* 其它月份日期颜色
*/
protected Paint mOtherMonthTextPaint = new Paint();
/**
* 当前月份农历文本颜色
*/
protected Paint mCurMonthLunarTextPaint = new Paint();
/**
* 当前月份农历文本颜色
*/
protected Paint mSelectedLunarTextPaint = new Paint();
/**
* 其它月份农历文本颜色
*/
protected Paint mOtherMonthLunarTextPaint = new Paint();
/**
* 其它月份农历文本颜色
*/
protected Paint mSchemeLunarTextPaint = new Paint();
/**
* 标记的日期背景颜色画笔
*/
protected Paint mSchemePaint = new Paint();
/**
* 被选择的日期背景色
*/
protected Paint mSelectedPaint = new Paint();
/**
* 标记的文本画笔
*/
protected Paint mSchemeTextPaint = new Paint();
/**
* 选中的文本画笔
*/
protected Paint mSelectTextPaint = new Paint();
/**
* 当前日期文本颜色画笔
*/
protected Paint mCurDayTextPaint = new Paint();
/**
* 当前日期文本颜色画笔
*/
protected Paint mCurDayLunarTextPaint = new Paint();
/**
* 日历布局,需要在日历下方放自己的布局
*/
CalendarLayout mParentLayout;
/**
* 日历项
*/
protected List<Calendar> mItems;
/**
* 每一项的高度
*/
protected int mItemHeight;
/**
* 每一项的宽度
*/
protected int mItemWidth;
/**
* Text的基线
*/
protected float mTextBaseLine;
/**
* 点击的x、y坐标
*/
protected float mX, mY;
/**
* 是否点击
*/
boolean isClick = true;
/**
* 字体大小
*/
static final int TEXT_SIZE = 14;
/**
* 当前点击项
*/
int mCurrentItem = -1;
/**
* 周起始
*/
int mWeekStartWidth;
public BaseView(Context context) {
this(context, null);
}
public BaseView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint(context);
}
/**
* 初始化配置
*
* @param context context
*/
private void initPaint(Context context) {
mCurMonthTextPaint.setAntiAlias(true);
mCurMonthTextPaint.setTextAlign(Paint.Align.CENTER);
mCurMonthTextPaint.setColor(0xFF111111);
mCurMonthTextPaint.setFakeBoldText(true);
mCurMonthTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mOtherMonthTextPaint.setAntiAlias(true);
mOtherMonthTextPaint.setTextAlign(Paint.Align.CENTER);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthTextPaint.setFakeBoldText(true);
mOtherMonthTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mCurMonthLunarTextPaint.setAntiAlias(true);
mCurMonthLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mSelectedLunarTextPaint.setAntiAlias(true);
mSelectedLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mOtherMonthLunarTextPaint.setAntiAlias(true);
mOtherMonthLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeLunarTextPaint.setAntiAlias(true);
mSchemeLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeTextPaint.setAntiAlias(true);
mSchemeTextPaint.setStyle(Paint.Style.FILL);
mSchemeTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeTextPaint.setColor(0xffed5353);
mSchemeTextPaint.setFakeBoldText(true);
mSchemeTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mSelectTextPaint.setAntiAlias(true);
mSelectTextPaint.setStyle(Paint.Style.FILL);
mSelectTextPaint.setTextAlign(Paint.Align.CENTER);
mSelectTextPaint.setColor(0xffed5353);
mSelectTextPaint.setFakeBoldText(true);
mSelectTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mSchemePaint.setAntiAlias(true);
mSchemePaint.setStyle(Paint.Style.FILL);
mSchemePaint.setStrokeWidth(2);
mSchemePaint.setColor(0xffefefef);
mCurDayTextPaint.setAntiAlias(true);
mCurDayTextPaint.setTextAlign(Paint.Align.CENTER);
mCurDayTextPaint.setColor(Color.RED);
mCurDayTextPaint.setFakeBoldText(true);
mCurDayTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mCurDayLunarTextPaint.setAntiAlias(true);
mCurDayLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mCurDayLunarTextPaint.setColor(Color.RED);
mCurDayLunarTextPaint.setFakeBoldText(true);
mCurDayLunarTextPaint.setTextSize(CalendarUtil.dipToPx(context, TEXT_SIZE));
mSelectedPaint.setAntiAlias(true);
mSelectedPaint.setStyle(Paint.Style.FILL);
mSelectedPaint.setStrokeWidth(2);
setOnClickListener(this);
setOnLongClickListener(this);
}
/**
* 初始化所有UI配置
*
* @param delegate delegate
*/
final void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
mWeekStartWidth = mDelegate.getWeekStart();
updateStyle();
updateItemHeight();
initPaint();
}
final void updateStyle() {
if (mDelegate == null) {
return;
}
this.mCurDayTextPaint.setColor(mDelegate.getCurDayTextColor());
this.mCurDayLunarTextPaint.setColor(mDelegate.getCurDayLunarTextColor());
this.mCurMonthTextPaint.setColor(mDelegate.getCurrentMonthTextColor());
this.mOtherMonthTextPaint.setColor(mDelegate.getOtherMonthTextColor());
this.mCurMonthLunarTextPaint.setColor(mDelegate.getCurrentMonthLunarTextColor());
this.mSelectedLunarTextPaint.setColor(mDelegate.getSelectedLunarTextColor());
this.mSelectTextPaint.setColor(mDelegate.getSelectedTextColor());
this.mOtherMonthLunarTextPaint.setColor(mDelegate.getOtherMonthLunarTextColor());
this.mSchemeLunarTextPaint.setColor(mDelegate.getSchemeLunarTextColor());
this.mSchemePaint.setColor(mDelegate.getSchemeThemeColor());
this.mSchemeTextPaint.setColor(mDelegate.getSchemeTextColor());
this.mCurMonthTextPaint.setTextSize(mDelegate.getDayTextSize());
this.mOtherMonthTextPaint.setTextSize(mDelegate.getDayTextSize());
this.mCurDayTextPaint.setTextSize(mDelegate.getDayTextSize());
this.mSchemeTextPaint.setTextSize(mDelegate.getDayTextSize());
this.mSelectTextPaint.setTextSize(mDelegate.getDayTextSize());
this.mCurMonthLunarTextPaint.setTextSize(mDelegate.getLunarTextSize());
this.mSelectedLunarTextPaint.setTextSize(mDelegate.getLunarTextSize());
this.mCurDayLunarTextPaint.setTextSize(mDelegate.getLunarTextSize());
this.mOtherMonthLunarTextPaint.setTextSize(mDelegate.getLunarTextSize());
this.mSchemeLunarTextPaint.setTextSize(mDelegate.getLunarTextSize());
this.mSelectedPaint.setStyle(Paint.Style.FILL);
this.mSelectedPaint.setColor(mDelegate.getSelectedThemeColor());
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
void updateItemHeight() {
this.mItemHeight = mDelegate.getCalendarItemHeight();
Paint.FontMetrics metrics = mCurMonthTextPaint.getFontMetrics();
mTextBaseLine = mItemHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
}
/**
* 移除事件
*/
final void removeSchemes() {
for (Calendar a : mItems) {
a.setScheme("");
a.setSchemeColor(0);
a.setSchemes(null);
}
}
/**
* 添加事件标记,来自Map
*/
final void addSchemesFromMap() {
if (mDelegate.mSchemeDatesMap == null || mDelegate.mSchemeDatesMap.size() == 0) {
return;
}
for (Calendar a : mItems) {
if (mDelegate.mSchemeDatesMap.containsKey(a.toString())) {
Calendar d = mDelegate.mSchemeDatesMap.get(a.toString());
if (d == null) {
continue;
}
a.setScheme(TextUtils.isEmpty(d.getScheme()) ? mDelegate.getSchemeText() : d.getScheme());
a.setSchemeColor(d.getSchemeColor());
a.setSchemes(d.getSchemes());
} else {
a.setScheme("");
a.setSchemeColor(0);
a.setSchemes(null);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 1)
return false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = event.getX();
mY = event.getY();
isClick = true;
break;
case MotionEvent.ACTION_MOVE:
float mDY;
if (isClick) {
mDY = event.getY() - mY;
isClick = Math.abs(mDY) <= 50;
}
break;
case MotionEvent.ACTION_UP:
mX = event.getX();
mY = event.getY();
break;
}
return super.onTouchEvent(event);
}
/**
* 开始绘制前的钩子,这里做一些初始化的操作,每次绘制只调用一次,性能高效
* 没有需要可忽略不实现
* 例如:
* 1、需要绘制圆形标记事件背景,可以在这里计算半径
* 2、绘制矩形选中效果,也可以在这里计算矩形宽和高
*/
protected void onPreviewHook() {
// TODO: 2017/11/16
}
/**
* 是否是选中的
*
* @param calendar calendar
* @return true or false
*/
protected boolean isSelected(Calendar calendar) {
return mItems != null && mItems.indexOf(calendar) == mCurrentItem;
}
/**
* 更新事件
*/
final void update() {
if (mDelegate.mSchemeDatesMap == null || mDelegate.mSchemeDatesMap.size() == 0) {//清空操作
removeSchemes();
invalidate();
return;
}
addSchemesFromMap();
invalidate();
}
/**
* 是否拦截日期,此设置续设置mCalendarInterceptListener
*
* @param calendar calendar
* @return 是否拦截日期
*/
protected final boolean onCalendarIntercept(Calendar calendar) {
return mDelegate.mCalendarInterceptListener != null &&
mDelegate.mCalendarInterceptListener.onCalendarIntercept(calendar);
}
/**
* 是否在日期范围内
*
* @param calendar calendar
* @return 是否在日期范围内
*/
protected final boolean isInRange(Calendar calendar) {
return mDelegate != null && CalendarUtil.isCalendarInRange(calendar, mDelegate);
}
/**
* 跟新当前日期
*/
abstract void updateCurrentDate();
/**
* 销毁
*/
protected abstract void onDestroy();
protected int getWeekStartWith() {
return mDelegate != null ? mDelegate.getWeekStart() : CalendarViewDelegate.WEEK_START_WITH_SUN;
}
protected int getCalendarPaddingLeft() {
return mDelegate != null ? mDelegate.getCalendarPaddingLeft() : 0;
}
protected int getCalendarPaddingRight() {
return mDelegate != null ? mDelegate.getCalendarPaddingRight() : 0;
}
/**
* 初始化画笔相关
*/
protected void initPaint() {
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
/**
* 最基础周视图,因为日历UI采用热插拔实现,所以这里必须继承实现,达到UI一致即可
* 可通过此扩展各种视图如:WeekView、RangeWeekView
*/
public abstract class BaseWeekView extends BaseView {
public BaseWeekView(Context context) {
super(context);
}
/**
* 初始化周视图控件
*
* @param calendar calendar
*/
final void setup(Calendar calendar) {
mItems = CalendarUtil.initCalendarForWeekView(calendar, mDelegate, mDelegate.getWeekStart());
addSchemesFromMap();
invalidate();
}
/**
* 记录已经选择的日期
*
* @param calendar calendar
*/
final void setSelectedCalendar(Calendar calendar) {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_SINGLE &&
!calendar.equals(mDelegate.mSelectedCalendar)) {
return;
}
mCurrentItem = mItems.indexOf(calendar);
}
/**
* 周视图切换点击默认位置
*
* @param calendar calendar
* @param isNotice isNotice
*/
final void performClickCalendar(Calendar calendar, boolean isNotice) {
if (mParentLayout == null ||
mDelegate.mInnerListener == null ||
mItems == null || mItems.size() == 0) {
return;
}
int week = CalendarUtil.getWeekViewIndexFromCalendar(calendar, mDelegate.getWeekStart());
if (mItems.contains(mDelegate.getCurrentDay())) {
week = CalendarUtil.getWeekViewIndexFromCalendar(mDelegate.getCurrentDay(), mDelegate.getWeekStart());
}
int curIndex = week;
Calendar currentCalendar = mItems.get(week);
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_DEFAULT) {
if (mItems.contains(mDelegate.mSelectedCalendar)) {
currentCalendar = mDelegate.mSelectedCalendar;
} else {
mCurrentItem = -1;
}
}
if (!isInRange(currentCalendar)) {
curIndex = getEdgeIndex(isMinRangeEdge(currentCalendar));
currentCalendar = mItems.get(curIndex);
}
currentCalendar.setCurrentDay(currentCalendar.equals(mDelegate.getCurrentDay()));
mDelegate.mInnerListener.onWeekDateSelected(currentCalendar, false);
int i = CalendarUtil.getWeekFromDayInMonth(currentCalendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
if (mDelegate.mCalendarSelectListener != null
&& isNotice
&& mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
mDelegate.mCalendarSelectListener.onCalendarSelect(currentCalendar, false);
}
mParentLayout.updateContentViewTranslateY();
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
mCurrentItem = curIndex;
}
if (!mDelegate.isShowYearSelectedLayout &&
mDelegate.mIndexCalendar != null &&
calendar.getYear() != mDelegate.mIndexCalendar.getYear() &&
mDelegate.mYearChangeListener != null) {
mDelegate.mYearChangeListener.onYearChange(mDelegate.mIndexCalendar.getYear());
}
mDelegate.mIndexCalendar = currentCalendar;
invalidate();
}
/**
* 是否是最小访问边界了
*
* @param calendar calendar
* @return 是否是最小访问边界了
*/
final boolean isMinRangeEdge(Calendar calendar) {
java.util.Calendar c = java.util.Calendar.getInstance();
c.set(mDelegate.getMinYear(), mDelegate.getMinYearMonth() - 1, mDelegate.getMinYearDay());
long minTime = c.getTimeInMillis();
c.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay());
long curTime = c.getTimeInMillis();
return curTime < minTime;
}
/**
* 获得边界范围内下标
*
* @param isMinEdge isMinEdge
* @return 获得边界范围内下标
*/
final int getEdgeIndex(boolean isMinEdge) {
for (int i = 0; i < mItems.size(); i++) {
Calendar item = mItems.get(i);
boolean isInRange = isInRange(item);
if (isMinEdge && isInRange) {
return i;
} else if (!isMinEdge && !isInRange) {
return i - 1;
}
}
return isMinEdge ? 6 : 0;
}
/**
* 获取点击的日历
*
* @return 获取点击的日历
*/
protected Calendar getIndex() {
if (mX <= mDelegate.getCalendarPaddingLeft() || mX >= getWidth() - mDelegate.getCalendarPaddingRight()) {
onClickCalendarPadding();
return null;
}
int indexX = (int) (mX - mDelegate.getCalendarPaddingLeft()) / mItemWidth;
if (indexX >= 7) {
indexX = 6;
}
int indexY = (int) mY / mItemHeight;
int position = indexY * 7 + indexX;// 选择项
if (position >= 0 && position < mItems.size())
return mItems.get(position);
return null;
}
private void onClickCalendarPadding() {
if (mDelegate.mClickCalendarPaddingListener == null) {
return;
}
Calendar calendar = null;
int indexX = (int) (mX - mDelegate.getCalendarPaddingLeft()) / mItemWidth;
if (indexX >= 7) {
indexX = 6;
}
int indexY = (int) mY / mItemHeight;
int position = indexY * 7 + indexX;// 选择项
if (position >= 0 && position < mItems.size()) {
calendar = mItems.get(position);
}
if (calendar == null) {
return;
}
mDelegate.mClickCalendarPaddingListener.onClickCalendarPadding(mX, mY, false, calendar,
getClickCalendarPaddingObject(mX, mY, calendar));
}
/**
* /**
* 获取点击事件处的对象
*
* @param x x
* @param y y
* @param adjacentCalendar adjacent calendar
* @return obj can as null
*/
@SuppressWarnings("unused")
protected Object getClickCalendarPaddingObject(float x, float y, Calendar adjacentCalendar) {
return null;
}
/**
* 更新显示模式
*/
final void updateShowMode() {
invalidate();
}
/**
* 更新周起始
*/
final void updateWeekStart() {
int position = (int) getTag();
Calendar calendar = CalendarUtil.getFirstCalendarStartWithMinCalendar(mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
position + 1,
mDelegate.getWeekStart());
setSelectedCalendar(mDelegate.mSelectedCalendar);
setup(calendar);
}
/**
* 更新当选模式
*/
final void updateSingleSelect() {
if (!mItems.contains(mDelegate.mSelectedCalendar)) {
mCurrentItem = -1;
invalidate();
}
}
@Override
void updateCurrentDate() {
if (mItems == null)
return;
if (mItems.contains(mDelegate.getCurrentDay())) {
for (Calendar a : mItems) {//添加操作
a.setCurrentDay(false);
}
int index = mItems.indexOf(mDelegate.getCurrentDay());
mItems.get(index).setCurrentDay(true);
}
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 开始绘制前的钩子,这里做一些初始化的操作,每次绘制只调用一次,性能高效
* 没有需要可忽略不实现
* 例如:
* 1、需要绘制圆形标记事件背景,可以在这里计算半径
* 2、绘制矩形选中效果,也可以在这里计算矩形宽和高
*/
protected void onPreviewHook() {
// TODO: 2017/11/16
}
/**
* 循环绘制开始的回调,不需要可忽略
* 绘制每个日历项的循环,用来计算baseLine、圆心坐标等都可以在这里实现
*
* @param x 日历Card x起点坐标
*/
@SuppressWarnings("unused")
protected void onLoopStart(int x) {
// TODO: 2017/11/16
}
@Override
protected void onDestroy() {
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.text.TextUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
/**
* 日历对象、
*/
@SuppressWarnings("all")
public final class Calendar implements Serializable, Comparable<Calendar> {
private static final long serialVersionUID = 141315161718191143L;
/**
* 时区
*/
private String zone;
/**
* 年
*/
private int year;
/**
* 月1-12
*/
private int month;
/**
* 如果是闰月,则返回闰月
*/
private int leapMonth;
/**
* 日1-31
*/
private int day;
/**
* 是否是闰年
*/
private boolean isLeapYear;
/**
* 是否是本月,这里对应的是月视图的本月,而非当前月份,请注意
*/
private boolean isCurrentMonth;
/**
* 是否是今天
*/
private boolean isCurrentDay;
/**
* 农历字符串,没有特别大的意义,用来做简单的农历或者节日标记
* 建议通过lunarCakendar获取完整的农历日期
*/
private String lunar;
/**
* 24节气
*/
private String solarTerm;
/**
* 公历节日
*/
private String gregorianFestival;
/**
* 传统农历节日
*/
private String traditionFestival;
/**
* 计划,可以用来标记当天是否有任务,这里是默认的,如果使用多标记,请使用下面API
* using addScheme(int schemeColor,String scheme); multi scheme
*/
private String scheme;
/**
* 各种自定义标记颜色、没有则选择默认颜色,如果使用多标记,请使用下面API
* using addScheme(int schemeColor,String scheme); multi scheme
*/
private int schemeColor;
/**
* 多标记
* multi scheme,using addScheme();
*/
private List<Scheme> schemes;
/**
* 是否是周末
*/
private boolean isWeekend;
/**
* 星期,0-6 对应周日到周一
*/
private int week;
/**
* 获取完整的农历日期
*/
private Calendar lunarCalendar;
public void setZone(String zone){
this.zone = zone;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public boolean isCurrentMonth() {
return isCurrentMonth;
}
public void setCurrentMonth(boolean currentMonth) {
this.isCurrentMonth = currentMonth;
}
public boolean isCurrentDay() {
return isCurrentDay;
}
public void setCurrentDay(boolean currentDay) {
isCurrentDay = currentDay;
}
public String getLunar() {
return lunar;
}
public void setLunar(String lunar) {
this.lunar = lunar;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public int getSchemeColor() {
return schemeColor;
}
public void setSchemeColor(int schemeColor) {
this.schemeColor = schemeColor;
}
public List<Scheme> getSchemes() {
return schemes;
}
public void setSchemes(List<Scheme> schemes) {
this.schemes = schemes;
}
public void addScheme(Scheme scheme) {
if (schemes == null) {
schemes = new ArrayList<>();
}
schemes.add(scheme);
}
public void addScheme(int schemeColor, String scheme) {
if (schemes == null) {
schemes = new ArrayList<>();
}
schemes.add(new Scheme(schemeColor, scheme));
}
public void addScheme(int type, int schemeColor, String scheme) {
if (schemes == null) {
schemes = new ArrayList<>();
}
schemes.add(new Scheme(type, schemeColor, scheme));
}
public void addScheme(int type, int schemeColor, String scheme, String other) {
if (schemes == null) {
schemes = new ArrayList<>();
}
schemes.add(new Scheme(type, schemeColor, scheme, other));
}
public void addScheme(int schemeColor, String scheme, String other) {
if (schemes == null) {
schemes = new ArrayList<>();
}
schemes.add(new Scheme(schemeColor, scheme, other));
}
public boolean isWeekend() {
return isWeekend;
}
public void setWeekend(boolean weekend) {
isWeekend = weekend;
}
public int getWeek() {
return week;
}
public void setWeek(int week) {
this.week = week;
}
public Calendar getLunarCalendar() {
return lunarCalendar;
}
public void setLunarCalendar(Calendar lunarCakendar) {
this.lunarCalendar = lunarCakendar;
}
public String getSolarTerm() {
return solarTerm;
}
public void setSolarTerm(String solarTerm) {
this.solarTerm = solarTerm;
}
public String getGregorianFestival() {
return gregorianFestival;
}
public void setGregorianFestival(String gregorianFestival) {
this.gregorianFestival = gregorianFestival;
}
public int getLeapMonth() {
return leapMonth;
}
public void setLeapMonth(int leapMonth) {
this.leapMonth = leapMonth;
}
public boolean isLeapYear() {
return isLeapYear;
}
public void setLeapYear(boolean leapYear) {
isLeapYear = leapYear;
}
public String getTraditionFestival() {
return traditionFestival;
}
public void setTraditionFestival(String traditionFestival) {
this.traditionFestival = traditionFestival;
}
public boolean hasScheme() {
if (schemes != null && schemes.size() != 0) {
return true;
}
if (!TextUtils.isEmpty(scheme)) {
return true;
}
return false;
}
/**
* 是否是相同月份
*
* @param calendar 日期
* @return 是否是相同月份
*/
public boolean isSameMonth(Calendar calendar) {
return year == calendar.getYear() && month == calendar.getMonth();
}
/**
* 比较日期
*
* @param calendar 日期
* @return <0 0 >0
*/
public int compareTo(Calendar calendar) {
if (calendar == null) {
return 1;
}
return toString().compareTo(calendar.toString());
}
/**
* 运算差距多少天
*
* @param calendar calendar
* @return 运算差距多少天
*/
public final int differ(Calendar calendar) {
return CalendarUtil.differ(this, calendar);
}
/**
* 日期是否可用
*
* @return 日期是否可用
*/
public boolean isAvailable() {
return year > 0 & month > 0 & day > 0 & day <=31 & month <= 12 & year >= 1900 & year <= 2099;
}
/**
* 获取当前日历对应时间戳
*
* @return getTimeInMillis
*/
public long getTimeInMillis() {
java.util.Calendar calendar = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)){
calendar.setTimeZone(TimeZone.getTimeZone(zone));
}
calendar.set(java.util.Calendar.YEAR, year);
calendar.set(java.util.Calendar.MONTH, month - 1);
calendar.set(java.util.Calendar.DAY_OF_MONTH, day);
return calendar.getTimeInMillis();
}
@Override
public boolean equals(Object o) {
if (o != null && o instanceof Calendar) {
if (((Calendar) o).getYear() == year && ((Calendar) o).getMonth() == month && ((Calendar) o).getDay() == day)
return true;
}
return super.equals(o);
}
@Override
public String toString() {
return year + "" + (month < 10 ? "0" + month : month) + "" + (day < 10 ? "0" + day : day);
}
// @Override
// public int compare(Calendar lhs, Calendar rhs) {
// if (lhs == null || rhs == null) {
// return 0;
// }
// int result = lhs.compareTo(rhs);
// return result;
// }
final void mergeScheme(Calendar calendar, String defaultScheme) {
if (calendar == null)
return;
setScheme(TextUtils.isEmpty(calendar.getScheme()) ?
defaultScheme : calendar.getScheme());
setSchemeColor(calendar.getSchemeColor());
setSchemes(calendar.getSchemes());
}
final void clearScheme() {
setScheme("");
setSchemeColor(0);
setSchemes(null);
}
/**
* 事件标记服务,现在多类型的事务标记建议使用这个
*/
public final static class Scheme implements Serializable {
private int type;
private int shcemeColor;
private String scheme;
private String other;
private Object obj;
public Scheme() {
}
public Scheme(int type, int shcemeColor, String scheme, String other) {
this.type = type;
this.shcemeColor = shcemeColor;
this.scheme = scheme;
this.other = other;
}
public Scheme(int type, int shcemeColor, String scheme) {
this.type = type;
this.shcemeColor = shcemeColor;
this.scheme = scheme;
}
public Scheme(int shcemeColor, String scheme) {
this.shcemeColor = shcemeColor;
this.scheme = scheme;
}
public Scheme(int shcemeColor, String scheme, String other) {
this.shcemeColor = shcemeColor;
this.scheme = scheme;
this.other = other;
}
public int getShcemeColor() {
return shcemeColor;
}
public void setShcemeColor(int shcemeColor) {
this.shcemeColor = shcemeColor;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import com.sobot.widget.R;
/**
* 日历布局
*/
@SuppressWarnings("unused")
public class CalendarLayout extends LinearLayout {
/**
* 多点触控支持
*/
private int mActivePointerId;
private static final int ACTIVE_POINTER = 1;
private static final int INVALID_POINTER = -1;
/**
* 周月视图
*/
private static final int CALENDAR_SHOW_MODE_BOTH_MONTH_WEEK_VIEW = 0;
/**
* 仅周视图
*/
private static final int CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW = 1;
/**
* 仅月视图
*/
private static final int CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW = 2;
/**
* 默认展开
*/
private static final int STATUS_EXPAND = 0;
/**
* 默认收缩
*/
private static final int STATUS_SHRINK = 1;
/**
* 默认状态
*/
private int mDefaultStatus;
private boolean isWeekView;
/**
* 星期栏
*/
WeekBar mWeekBar;
/**
* 自定义ViewPager,月视图
*/
MonthViewPager mMonthView;
/**
* 日历
*/
CalendarView mCalendarView;
/**
* 自定义的周视图
*/
WeekViewPager mWeekPager;
/**
* 年视图
*/
YearViewPager mYearView;
/**
* ContentView
*/
ViewGroup mContentView;
/**
* 默认手势
*/
private static final int GESTURE_MODE_DEFAULT = 0;
// /**
// * 仅日历有效
// */
// private static final int GESTURE_MODE_ONLY_CALENDAR = 1;
/**
* 禁用手势
*/
private static final int GESTURE_MODE_DISABLED = 2;
/**
* 手势模式
*/
private int mGestureMode;
private int mCalendarShowMode;
private int mContentViewTranslateY; //ContentView 可滑动的最大距离距离 , 固定
private int mViewPagerTranslateY = 0;// ViewPager可以平移的距离,不代表mMonthView的平移距离
private float downY;
private float mLastY;
private float mLastX;
private boolean isAnimating = false;
/**
* 内容布局id
*/
private int mContentViewId;
/**
* 手速判断
*/
private VelocityTracker mVelocityTracker;
private int mMaximumVelocity;
private int mItemHeight;
private CalendarViewDelegate mDelegate;
public CalendarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Sobot_CalendarLayout);
mContentViewId = array.getResourceId(R.styleable.Sobot_CalendarLayout_calendar_content_view_id, 0);
mDefaultStatus = array.getInt(R.styleable.Sobot_CalendarLayout_default_status, STATUS_EXPAND);
mCalendarShowMode = array.getInt(R.styleable.Sobot_CalendarLayout_calendar_show_mode, CALENDAR_SHOW_MODE_BOTH_MONTH_WEEK_VIEW);
mGestureMode = array.getInt(R.styleable.Sobot_CalendarLayout_gesture_mode, GESTURE_MODE_DEFAULT);
array.recycle();
mVelocityTracker = VelocityTracker.obtain();
final ViewConfiguration configuration = ViewConfiguration.get(context);
int mTouchSlop = configuration.getScaledTouchSlop();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
/**
* 初始化
*
* @param delegate delegate
*/
final void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
mItemHeight = mDelegate.getCalendarItemHeight();
initCalendarPosition(delegate.mSelectedCalendar.isAvailable() ?
delegate.mSelectedCalendar :
delegate.createCurrentDate());
updateContentViewTranslateY();
}
/**
* 初始化当前时间的位置
*
* @param cur 当前日期时间
*/
private void initCalendarPosition(Calendar cur) {
int diff = CalendarUtil.getMonthViewStartDiff(cur, mDelegate.getWeekStart());
int size = diff + cur.getDay() - 1;
updateSelectPosition(size);
}
/**
* 当前第几项被选中,更新平移量
*
* @param selectPosition 月视图被点击的position
*/
final void updateSelectPosition(int selectPosition) {
int line = (selectPosition + 7) / 7;
mViewPagerTranslateY = (line - 1) * mItemHeight;
}
/**
* 设置选中的周,更新位置
*
* @param week week
*/
final void updateSelectWeek(int week) {
mViewPagerTranslateY = (week - 1) * mItemHeight;
}
/**
* 更新内容ContentView可平移的最大距离
*/
void updateContentViewTranslateY() {
Calendar calendar = mDelegate.mIndexCalendar;
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {
mContentViewTranslateY = 5 * mItemHeight;
} else {
mContentViewTranslateY = CalendarUtil.getMonthViewHeight(calendar.getYear(),
calendar.getMonth(), mItemHeight, mDelegate.getWeekStart())
- mItemHeight;
}
//已经显示周视图,则需要动态平移contentView的高度
if (mWeekPager.getVisibility() == VISIBLE) {
if (mContentView == null)
return;
mContentView.setTranslationY(-mContentViewTranslateY);
}
}
/**
* 更新日历项高度
*/
final void updateCalendarItemHeight() {
mItemHeight = mDelegate.getCalendarItemHeight();
if (mContentView == null)
return;
Calendar calendar = mDelegate.mIndexCalendar;
updateSelectWeek(CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart()));
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {
mContentViewTranslateY = 5 * mItemHeight;
} else {
mContentViewTranslateY = CalendarUtil.getMonthViewHeight(calendar.getYear(), calendar.getMonth(),
mItemHeight, mDelegate.getWeekStart()) - mItemHeight;
}
translationViewPager();
if (mWeekPager.getVisibility() == VISIBLE) {
mContentView.setTranslationY(-mContentViewTranslateY);
}
}
/**
* 隐藏日历
*/
public void hideCalendarView() {
if (mCalendarView == null) {
return;
}
mCalendarView.setVisibility(GONE);
if (!isExpand()) {
expand(0);
}
requestLayout();
}
/**
* 显示日历
*/
public void showCalendarView() {
mCalendarView.setVisibility(VISIBLE);
requestLayout();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGestureMode == GESTURE_MODE_DISABLED ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW) {//禁用手势,或者只显示某种视图
return false;
}
if (mDelegate == null) {
return false;
}
if (mDelegate.isShowYearSelectedLayout) {
return false;
}
if (mContentView == null || mCalendarView == null || mCalendarView.getVisibility() == GONE) {
return false;
}
int action = event.getAction();
float y = event.getY();
mVelocityTracker.addMovement(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
int index = event.getActionIndex();
mActivePointerId = event.getPointerId(index);
mLastY = downY = y;
return true;
case MotionEvent.ACTION_POINTER_DOWN: {
final int indexx = event.getActionIndex();
mActivePointerId = event.getPointerId(indexx);
if (mActivePointerId == 0) {
//核心代码:就是让下面的 dy = y- mLastY == 0,避免抖动
mLastY = event.getY(mActivePointerId);
}
break;
}
case MotionEvent.ACTION_MOVE:
getPointerIndex(event, mActivePointerId);
if (mActivePointerId == INVALID_POINTER) {
//如果切换了手指,那把mLastY换到最新手指的y坐标即可,核心就是让下面的 dy== 0,避免抖动
mLastY = y;
mActivePointerId = ACTIVE_POINTER;
}
float dy = y - mLastY;
//向上滑动,并且contentView平移到最大距离,显示周视图
if (dy < 0 && mContentView.getTranslationY() == -mContentViewTranslateY) {
mLastY = y;
event.setAction(MotionEvent.ACTION_DOWN);
dispatchTouchEvent(event);
mWeekPager.setVisibility(VISIBLE);
mMonthView.setVisibility(INVISIBLE);
if (!isWeekView && mDelegate.mViewChangeListener != null) {
mDelegate.mViewChangeListener.onViewChange(false);
}
isWeekView = true;
return true;
}
hideWeek(false);
//向下滑动,并且contentView已经完全平移到底部
if (dy > 0 && mContentView.getTranslationY() + dy >= 0) {
mContentView.setTranslationY(0);
translationViewPager();
mLastY = y;
return super.onTouchEvent(event);
}
//向上滑动,并且contentView已经平移到最大距离,则contentView平移到最大的距离
if (dy < 0 && mContentView.getTranslationY() + dy <= -mContentViewTranslateY) {
mContentView.setTranslationY(-mContentViewTranslateY);
translationViewPager();
mLastY = y;
return super.onTouchEvent(event);
}
//否则按比例平移
mContentView.setTranslationY(mContentView.getTranslationY() + dy);
translationViewPager();
mLastY = y;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_POINTER_UP:
int pointerIndex = getPointerIndex(event, mActivePointerId);
if (mActivePointerId == INVALID_POINTER)
break;
mLastY = event.getY(pointerIndex);
break;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
float mYVelocity = velocityTracker.getYVelocity();
if (mContentView.getTranslationY() == 0
|| mContentView.getTranslationY() == mContentViewTranslateY) {
expand();
break;
}
if (Math.abs(mYVelocity) >= 800) {
if (mYVelocity < 0) {
shrink();
} else {
expand();
}
return super.onTouchEvent(event);
}
if (event.getY() - downY > 0) {
expand();
} else {
shrink();
}
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (isAnimating) {
return super.dispatchTouchEvent(ev);
}
if (mGestureMode == GESTURE_MODE_DISABLED) {
return super.dispatchTouchEvent(ev);
}
if (mYearView == null ||
mCalendarView == null || mCalendarView.getVisibility() == GONE ||
mContentView == null ||
mContentView.getVisibility() != VISIBLE) {
return super.dispatchTouchEvent(ev);
}
if (mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW) {
return super.dispatchTouchEvent(ev);
}
if (mYearView.getVisibility() == VISIBLE || mDelegate.isShowYearSelectedLayout) {
return super.dispatchTouchEvent(ev);
}
final int action = ev.getAction();
float y = ev.getY();
if (action == MotionEvent.ACTION_MOVE) {
float dy = y - mLastY;
/*
* 如果向下滚动,有 2 种情况处理 且y在ViewPager下方
* 1、RecyclerView 或者其它滚动的View,当mContentView滚动到顶部时,拦截事件
* 2、非滚动控件,直接拦截事件
*/
if (dy > 0 && mContentView.getTranslationY() == -mContentViewTranslateY) {
if (isScrollTop()) {
requestDisallowInterceptTouchEvent(false);//父View向子View拦截分发事件
return super.dispatchTouchEvent(ev);
}
}
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isAnimating) {
return true;
}
if (mGestureMode == GESTURE_MODE_DISABLED) {
return false;
}
if (mYearView == null ||
mCalendarView == null || mCalendarView.getVisibility() == GONE ||
mContentView == null ||
mContentView.getVisibility() != VISIBLE) {
return super.onInterceptTouchEvent(ev);
}
if (mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW) {
return false;
}
if (mYearView.getVisibility() == VISIBLE || mDelegate.isShowYearSelectedLayout) {
return super.onInterceptTouchEvent(ev);
}
final int action = ev.getAction();
float y = ev.getY();
float x = ev.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
int index = ev.getActionIndex();
mActivePointerId = ev.getPointerId(index);
mLastY = downY = y;
mLastX = x;
break;
case MotionEvent.ACTION_MOVE:
float dy = y - mLastY;
float dx = x - mLastX;
/*
如果向上滚动,且ViewPager已经收缩,不拦截事件
*/
if (dy < 0 && mContentView.getTranslationY() == -mContentViewTranslateY) {
return false;
}
/*
* 如果向下滚动,有 2 种情况处理 且y在ViewPager下方
* 1、RecyclerView 或者其它滚动的View,当mContentView滚动到顶部时,拦截事件
* 2、非滚动控件,直接拦截事件
*/
if (dy > 0 && mContentView.getTranslationY() == -mContentViewTranslateY
&& y >= mDelegate.getCalendarItemHeight() + mDelegate.getWeekBarHeight()) {
if (!isScrollTop()) {
return false;
}
}
if (dy > 0 && mContentView.getTranslationY() == 0 && y >= CalendarUtil.dipToPx(getContext(), 98)) {
return false;
}
if (Math.abs(dy) > Math.abs(dx) ) { //纵向滑动距离大于横向滑动距离,拦截滑动事件
if ((dy > 0 && mContentView.getTranslationY() <= 0)
|| (dy < 0 && mContentView.getTranslationY() >= -mContentViewTranslateY)) {
mLastY = y;
return true;
}
}
break;
}
return super.onInterceptTouchEvent(ev);
}
private int getPointerIndex(MotionEvent ev, int id) {
int activePointerIndex = ev.findPointerIndex(id);
if (activePointerIndex == -1) {
mActivePointerId = INVALID_POINTER;
}
return activePointerIndex;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mContentView == null || mCalendarView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int year = mDelegate.mIndexCalendar.getYear();
int month = mDelegate.mIndexCalendar.getMonth();
int weekBarHeight = CalendarUtil.dipToPx(getContext(), 1)
+ mDelegate.getWeekBarHeight();
int monthHeight = CalendarUtil.getMonthViewHeight(year, month,
mDelegate.getCalendarItemHeight(),
mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode())
+ weekBarHeight;
int height = MeasureSpec.getSize(heightMeasureSpec);
if (mDelegate.isFullScreenCalendar()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightSpec = MeasureSpec.makeMeasureSpec(height - weekBarHeight - mDelegate.getCalendarItemHeight(),
MeasureSpec.EXACTLY);
mContentView.measure(widthMeasureSpec, heightSpec);
mContentView.layout(mContentView.getLeft(), mContentView.getTop(), mContentView.getRight(), mContentView.getBottom());
return;
}
if (monthHeight >= height && mMonthView.getHeight() > 0) {
height = monthHeight;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(monthHeight +
weekBarHeight +
mDelegate.getWeekBarHeight(), MeasureSpec.EXACTLY);
} else if (monthHeight < height && mMonthView.getHeight() > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
int h;
if (mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW ||
mCalendarView.getVisibility() == GONE) {
h = height - (mCalendarView.getVisibility() == GONE ? 0 : mCalendarView.getHeight());
} else if (mGestureMode == GESTURE_MODE_DISABLED && !isAnimating) {
if (isExpand()) {
h = height - monthHeight;
} else {
h = height - weekBarHeight - mItemHeight;
}
} else {
h = height - weekBarHeight - mItemHeight;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightSpec = MeasureSpec.makeMeasureSpec(h,
MeasureSpec.EXACTLY);
mContentView.measure(widthMeasureSpec, heightSpec);
mContentView.layout(mContentView.getLeft(), mContentView.getTop(), mContentView.getRight(), mContentView.getBottom());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMonthView = findViewById(R.id.vp_month);
mWeekPager = findViewById(R.id.vp_week);
if (getChildCount() > 0) {
mCalendarView = (CalendarView) getChildAt(0);
}
mContentView = findViewById(mContentViewId);
mYearView = findViewById(R.id.selectLayout);
}
/**
* 平移ViewPager月视图
*/
private void translationViewPager() {
float percent = mContentView.getTranslationY() * 1.0f / mContentViewTranslateY;
mMonthView.setTranslationY(mViewPagerTranslateY * percent);
}
public void setModeBothMonthWeekView() {
mCalendarShowMode = CALENDAR_SHOW_MODE_BOTH_MONTH_WEEK_VIEW;
requestLayout();
}
public void setModeOnlyWeekView() {
mCalendarShowMode = CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW;
requestLayout();
}
public void setModeOnlyMonthView() {
mCalendarShowMode = CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW;
requestLayout();
}
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
Parcelable parcelable = super.onSaveInstanceState();
bundle.putParcelable("super", parcelable);
bundle.putBoolean("isExpand", isExpand());
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
Parcelable superData = bundle.getParcelable("super");
boolean isExpand = bundle.getBoolean("isExpand");
if (isExpand) {
post(new Runnable() {
@Override
public void run() {
expand(0);
}
});
} else {
post(new Runnable() {
@Override
public void run() {
shrink(0);
}
});
}
super.onRestoreInstanceState(superData);
}
/**
* 是否展开了
*
* @return isExpand
*/
public final boolean isExpand() {
return mMonthView.getVisibility() == VISIBLE;
}
public boolean expand() {
return expand(240);
}
/**
* 展开
*
* @param duration 时长
* @return 展开是否成功
*/
public boolean expand(int duration) {
if (isAnimating ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW ||
mContentView == null)
return false;
if (mMonthView.getVisibility() != VISIBLE) {
mWeekPager.setVisibility(GONE);
onShowMonthView();
isWeekView = false;
mMonthView.setVisibility(VISIBLE);
}
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mContentView,
"translationY", mContentView.getTranslationY(), 0f);
objectAnimator.setDuration(duration);
objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (Float) animation.getAnimatedValue();
float percent = currentValue * 1.0f / mContentViewTranslateY;
mMonthView.setTranslationY(mViewPagerTranslateY * percent);
isAnimating = true;
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimating = false;
if (mGestureMode == GESTURE_MODE_DISABLED) {
requestLayout();
}
hideWeek(true);
if (mDelegate.mViewChangeListener != null && isWeekView) {
mDelegate.mViewChangeListener.onViewChange(true);
}
isWeekView = false;
}
});
objectAnimator.start();
return true;
}
public boolean shrink() {
return shrink(240);
}
/**
* 收缩
*
* @param duration 时长
* @return 成功或者失败
*/
public boolean shrink(int duration) {
if (mGestureMode == GESTURE_MODE_DISABLED) {
requestLayout();
}
if (isAnimating || mContentView == null) {
return false;
}
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mContentView,
"translationY", mContentView.getTranslationY(), -mContentViewTranslateY);
objectAnimator.setDuration(duration);
objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (Float) animation.getAnimatedValue();
float percent = currentValue * 1.0f / mContentViewTranslateY;
mMonthView.setTranslationY(mViewPagerTranslateY * percent);
isAnimating = true;
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimating = false;
showWeek();
isWeekView = true;
}
});
objectAnimator.start();
return true;
}
/**
* 初始化状态
*/
final void initStatus() {
if ((mDefaultStatus == STATUS_SHRINK ||
mCalendarShowMode == CALENDAR_SHOW_MODE_ONLY_WEEK_VIEW) &&
mCalendarShowMode != CALENDAR_SHOW_MODE_ONLY_MONTH_VIEW) {
if (mContentView == null) {
mWeekPager.setVisibility(VISIBLE);
mMonthView.setVisibility(GONE);
return;
}
post(new Runnable() {
@Override
public void run() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mContentView,
"translationY", mContentView.getTranslationY(), -mContentViewTranslateY);
objectAnimator.setDuration(0);
objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (Float) animation.getAnimatedValue();
float percent = currentValue * 1.0f / mContentViewTranslateY;
mMonthView.setTranslationY(mViewPagerTranslateY * percent);
isAnimating = true;
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimating = false;
isWeekView = true;
showWeek();
if (mDelegate == null || mDelegate.mViewChangeListener == null) {
return;
}
mDelegate.mViewChangeListener.onViewChange(false);
}
});
objectAnimator.start();
}
});
} else {
if (mDelegate.mViewChangeListener == null) {
return;
}
post(new Runnable() {
@Override
public void run() {
mDelegate.mViewChangeListener.onViewChange(true);
}
});
}
}
/**
* 隐藏周视图
*/
private void hideWeek(boolean isNotify) {
if (isNotify) {
onShowMonthView();
}
mWeekPager.setVisibility(GONE);
mMonthView.setVisibility(VISIBLE);
}
/**
* 显示周视图
*/
private void showWeek() {
onShowWeekView();
if (mWeekPager != null && mWeekPager.getAdapter() != null) {
mWeekPager.getAdapter().notifyDataSetChanged();
mWeekPager.setVisibility(VISIBLE);
}
mMonthView.setVisibility(INVISIBLE);
}
/**
* 周视图显示事件
*/
private void onShowWeekView() {
if (mWeekPager.getVisibility() == VISIBLE) {
return;
}
if (mDelegate != null && mDelegate.mViewChangeListener != null && !isWeekView) {
mDelegate.mViewChangeListener.onViewChange(false);
}
}
/**
* 周视图显示事件
*/
private void onShowMonthView() {
if (mMonthView.getVisibility() == VISIBLE) {
return;
}
if (mDelegate != null && mDelegate.mViewChangeListener != null && isWeekView) {
mDelegate.mViewChangeListener.onViewChange(true);
}
}
/**
* ContentView是否滚动到顶部 如果完全不适合,就复写这个方法
*
* @return 是否滚动到顶部
*/
protected boolean isScrollTop() {
if (mContentView instanceof CalendarScrollView) {
return ((CalendarScrollView) mContentView).isScrollToTop();
}
if (mContentView instanceof RecyclerView)
return ((RecyclerView) mContentView).computeVerticalScrollOffset() == 0;
if (mContentView instanceof AbsListView) {
boolean result = false;
AbsListView listView = (AbsListView) mContentView;
if (listView.getFirstVisiblePosition() == 0) {
final View topChildView = listView.getChildAt(0);
result = topChildView.getTop() == 0;
}
return result;
}
return mContentView.getScrollY() == 0;
}
/**
* 隐藏内容布局
*/
@SuppressLint("NewApi")
final void hideContentView() {
if (mContentView == null)
return;
mContentView.animate()
.translationY(getHeight() - mMonthView.getHeight())
.setDuration(220)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mContentView.setVisibility(INVISIBLE);
mContentView.clearAnimation();
}
});
}
/**
* 显示内容布局
*/
@SuppressLint("NewApi")
final void showContentView() {
if (mContentView == null)
return;
mContentView.setTranslationY(getHeight() - mMonthView.getHeight());
mContentView.setVisibility(VISIBLE);
mContentView.animate()
.translationY(0)
.setDuration(180)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
}
@SuppressWarnings("unused")
private int getCalendarViewHeight() {
return mMonthView.getVisibility() == VISIBLE ? mDelegate.getWeekBarHeight() + mMonthView.getHeight() :
mDelegate.getWeekBarHeight() + mDelegate.getCalendarItemHeight();
}
/**
* 如果有十分特别的ContentView,可以自定义实现这个接口
*/
public interface CalendarScrollView {
/**
* 是否滚动到顶部
*
* @return 是否滚动到顶部
*/
boolean isScrollToTop();
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* 一些日期辅助计算工具
*/
@SuppressWarnings("all")
public final class CalendarUtil {
public static String zone;
private static final long ONE_DAY = 1000 * 3600 * 24;
@SuppressLint("SimpleDateFormat")
static int getDate(String formatStr, Date date) {
SimpleDateFormat format = new SimpleDateFormat(formatStr);
if(!TextUtils.isEmpty(zone)) {
format.setTimeZone(TimeZone.getTimeZone(zone));
}
return Integer.parseInt(format.format(date));
}
/**
* 判断一个日期是否是周末,即周六日
*
* @param calendar calendar
* @return 判断一个日期是否是周末,即周六日
*/
public static boolean isWeekend(Calendar calendar) {
int week = getWeekFormCalendar(calendar);
return week == 0 || week == 6;
}
/**
* 获取某月的天数
*
* @param year 年
* @param month 月
* @return 某月的天数
*/
public static int getMonthDaysCount(int year, int month) {
int count = 0;
//判断大月份
if (month == 1 || month == 3 || month == 5 || month == 7
|| month == 8 || month == 10 || month == 12) {
count = 31;
}
//判断小月
if (month == 4 || month == 6 || month == 9 || month == 11) {
count = 30;
}
//判断平年与闰年
if (month == 2) {
if (isLeapYear(year)) {
count = 29;
} else {
count = 28;
}
}
return count;
}
/**
* 是否是闰年
*
* @param year year
* @return 是否是闰年
*/
public static boolean isLeapYear(int year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
public static int getMonthViewLineCount(int year, int month, int weekStartWith, int mode) {
if (mode == CalendarViewDelegate.MODE_ALL_MONTH) {
return 6;
}
int nextDiff = CalendarUtil.getMonthEndDiff(year, month, weekStartWith);
int preDiff = CalendarUtil.getMonthViewStartDiff(year, month, weekStartWith);
int monthDayCount = CalendarUtil.getMonthDaysCount(year, month);
return (preDiff + monthDayCount + nextDiff) / 7;
}
/**
* 获取月视图的确切高度
* Test pass
*
* @param year 年
* @param month 月
* @param itemHeight 每项的高度
* @param weekStartWith 周起始
* @return 不需要多余行的高度
*/
public static int getMonthViewHeight(int year, int month, int itemHeight, int weekStartWith) {
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(year, month - 1, 1, 12, 0, 0);
int preDiff = getMonthViewStartDiff(year, month, weekStartWith);
int monthDaysCount = getMonthDaysCount(year, month);
int nextDiff = getMonthEndDiff(year, month, monthDaysCount, weekStartWith);
return (preDiff + monthDaysCount + nextDiff) / 7 * itemHeight;
}
/**
* 获取月视图的确切高度
* Test pass
*
* @param year 年
* @param month 月
* @param itemHeight 每项的高度
* @param weekStartWith weekStartWith
* @param mode mode
* @return 不需要多余行的高度
*/
public static int getMonthViewHeight(int year, int month, int itemHeight, int weekStartWith, int mode) {
if (mode == CalendarViewDelegate.MODE_ALL_MONTH) {
return itemHeight * 6;
}
return getMonthViewHeight(year, month, itemHeight, weekStartWith);
}
/**
* 获取某天在该月的第几周,换言之就是获取这一天在该月视图的第几行,第几周,根据周起始动态获取
* Test pass,单元测试通过
*
* @param calendar calendar
* @param weekStart 其实星期是哪一天?
* @return 获取某天在该月的第几周 the week line in MonthView
*/
public static int getWeekFromDayInMonth(Calendar calendar, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(calendar.getYear(), calendar.getMonth() - 1, 1, 12, 0, 0);
//该月第一天为星期几,星期天 == 0
int diff = getMonthViewStartDiff(calendar, weekStart);
return (calendar.getDay() + diff - 1) / 7 + 1;
}
/**
* 获取上一个日子
*
* @param calendar calendar
* @return 获取上一个日子
*/
public static Calendar getPreCalendar(Calendar calendar) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay(), 12, 0, 0);//
long timeMills = date.getTimeInMillis();//获得起始时间戳
date.setTimeInMillis(timeMills - ONE_DAY);
Calendar preCalendar = new Calendar();
preCalendar.setYear(date.get(java.util.Calendar.YEAR));
preCalendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
preCalendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
return preCalendar;
}
public static Calendar getNextCalendar(Calendar calendar) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay(), 12, 0, 0);//
long timeMills = date.getTimeInMillis();//获得起始时间戳
date.setTimeInMillis(timeMills + ONE_DAY);
Calendar nextCalendar = new Calendar();
nextCalendar.setYear(date.get(java.util.Calendar.YEAR));
nextCalendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
nextCalendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
return nextCalendar;
}
/**
* DAY_OF_WEEK return 1 2 3 4 5 6 7,偏移了一位
* 获取日期所在月视图对应的起始偏移量
* Test pass
*
* @param calendar calendar
* @param weekStart weekStart 星期的起始
* @return 获取日期所在月视图对应的起始偏移量 the start diff with MonthView
*/
static int getMonthViewStartDiff(Calendar calendar, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(), calendar.getMonth() - 1, 1, 12, 0, 0);
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_SUN) {
return week - 1;
}
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_MON) {
return week == 1 ? 6 : week - weekStart;
}
return week == CalendarViewDelegate.WEEK_START_WITH_SAT ? 0 : week;
}
/**
* DAY_OF_WEEK return 1 2 3 4 5 6 7,偏移了一位
* 获取日期所在月视图对应的起始偏移量
* Test pass
*
* @param year 年
* @param month 月
* @param weekStart 周起始
* @return 获取日期所在月视图对应的起始偏移量 the start diff with MonthView
*/
static int getMonthViewStartDiff(int year, int month, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(year, month - 1, 1, 12, 0, 0);
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_SUN) {
return week - 1;
}
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_MON) {
return week == 1 ? 6 : week - weekStart;
}
return week == CalendarViewDelegate.WEEK_START_WITH_SAT ? 0 : week;
}
/**
* DAY_OF_WEEK return 1 2 3 4 5 6 7,偏移了一位
* 获取日期月份对应的结束偏移量,用于计算两个年份之间总共有多少周,不用于MonthView
* Test pass
*
* @param year 年
* @param month 月
* @param weekStart 周起始
* @return 获取日期月份对应的结束偏移量 the end diff in Month not MonthView
*/
static int getMonthEndDiff(int year, int month, int weekStart) {
return getMonthEndDiff(year, month, getMonthDaysCount(year, month), weekStart);
}
/**
* DAY_OF_WEEK return 1 2 3 4 5 6 7,偏移了一位
* 获取日期月份对应的结束偏移量,用于计算两个年份之间总共有多少周,不用于MonthView
* Test pass
*
* @param year 年
* @param month 月
* @param weekStart 周起始
* @return 获取日期月份对应的结束偏移量 the end diff in Month not MonthView
*/
private static int getMonthEndDiff(int year, int month, int day, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(year, month - 1, day);
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_SUN) {
return 7 - week;
}
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_MON) {
return week == 1 ? 0 : 7 - week + 1;
}
return week == 7 ? 6 : 7 - week - 1;
}
/**
* 获取某个日期是星期几
* 测试通过
*
* @param calendar 某个日期
* @return 返回某个日期是星期几
*/
static int getWeekFormCalendar(Calendar calendar) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay());
return date.get(java.util.Calendar.DAY_OF_WEEK) - 1;
}
/**
* 获取周视图的切换默认选项位置 WeekView index
* 测试通过 test pass
*
* @param calendar calendar
* @param weekStart weekStart
* @return 获取周视图的切换默认选项位置
*/
static int getWeekViewIndexFromCalendar(Calendar calendar, int weekStart) {
return getWeekViewStartDiff(calendar.getYear(), calendar.getMonth(), calendar.getDay(), weekStart);
}
/**
* 是否在日期范围內
* 测试通过 test pass
*
* @param calendar calendar
* @param minYear minYear
* @param minYearDay 最小年份天
* @param minYearMonth minYearMonth
* @param maxYear maxYear
* @param maxYearMonth maxYearMonth
* @param maxYearDay 最大年份天
* @return 是否在日期范围內
*/
static boolean isCalendarInRange(Calendar calendar,
int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay) {
java.util.Calendar c = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
c.setTimeZone(TimeZone.getTimeZone(zone));
}
c.set(minYear, minYearMonth - 1, minYearDay);
long minTime = c.getTimeInMillis();
c.set(maxYear, maxYearMonth - 1, maxYearDay);
long maxTime = c.getTimeInMillis();
c.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay());
long curTime = c.getTimeInMillis();
return curTime >= minTime && curTime <= maxTime;
}
/**
* 获取两个日期之间一共有多少周,
* 注意周起始周一、周日、周六
* 测试通过 test pass
*
* @param minYear minYear 最小年份
* @param minYearMonth maxYear 最小年份月份
* @param minYearDay 最小年份天
* @param maxYear maxYear 最大年份
* @param maxYearMonth maxYear 最大年份月份
* @param maxYearDay 最大年份天
* @param weekStart 周起始
* @return 周数用于WeekViewPager itemCount
*/
public static int getWeekCountBetweenBothCalendar(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay,
int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(minYear, minYearMonth - 1, minYearDay);
long minTimeMills = date.getTimeInMillis();//给定时间戳
int preDiff = getWeekViewStartDiff(minYear, minYearMonth, minYearDay, weekStart);
date.set(maxYear, maxYearMonth - 1, maxYearDay);
long maxTimeMills = date.getTimeInMillis();//给定时间戳
int nextDiff = getWeekViewEndDiff(maxYear, maxYearMonth, maxYearDay, weekStart);
int count = preDiff + nextDiff;
int c = (int) ((maxTimeMills - minTimeMills) / ONE_DAY) + 1;
count += c;
return count / 7;
}
/**
* 根据日期获取距离最小日期在第几周
* 用来设置 WeekView currentItem
* 测试通过 test pass
*
* @param calendar calendar
* @param minYear minYear 最小年份
* @param minYearMonth maxYear 最小年份月份
* @param minYearDay 最小年份天
* @param weekStart 周起始
* @return 返回两个年份中第几周 the WeekView currentItem
*/
public static int getWeekFromCalendarStartWithMinCalendar(Calendar calendar,
int minYear, int minYearMonth, int minYearDay,
int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(minYear, minYearMonth - 1, minYearDay);//起始日期
long firstTimeMill = date.getTimeInMillis();//获得范围起始时间戳
int preDiff = getWeekViewStartDiff(minYear, minYearMonth, minYearDay, weekStart);//范围起始的周偏移量
int weekStartDiff = getWeekViewStartDiff(calendar.getYear(),
calendar.getMonth(),
calendar.getDay(),
weekStart);//获取点击的日子在周视图的起始,为了兼容全球时区,最大日差为一天,如果周起始偏差weekStartDiff=0,则日期加1
date.set(calendar.getYear(),
calendar.getMonth() - 1,
weekStartDiff == 0 ? calendar.getDay() + 1 : calendar.getDay());
long curTimeMills = date.getTimeInMillis();//给定时间戳
int c = (int) ((curTimeMills - firstTimeMill) / ONE_DAY);
int count = preDiff + c;
return count / 7 + 1;
}
/**
* 根据星期数和最小日期推算出该星期的第一天,
* 为了防止夏令时,导致的时间提前和延后1-2小时,导致日期出现误差1天,因此吧hourOfDay = 12
* //测试通过 Test pass
*
* @param minYear 最小年份如2017
* @param minYearMonth maxYear 最小年份月份,like : 2017-07
* @param minYearDay 最小年份天
* @param week 从最小年份minYear月minYearMonth 日1 开始的第几周 week > 0
* @param weekStart 周起始
* @return 该星期的第一天日期
*/
public static Calendar getFirstCalendarStartWithMinCalendar(int minYear, int minYearMonth, int minYearDay, int week, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(minYear, minYearMonth - 1, minYearDay, 12, 0);//
long firstTimeMills = date.getTimeInMillis();//获得起始时间戳
long weekTimeMills = (week - 1) * 7 * ONE_DAY;
long timeCountMills = weekTimeMills + firstTimeMills;
date.setTimeInMillis(timeCountMills);
int startDiff = getWeekViewStartDiff(date.get(java.util.Calendar.YEAR),
date.get(java.util.Calendar.MONTH) + 1,
date.get(java.util.Calendar.DAY_OF_MONTH), weekStart);
timeCountMills -= startDiff * ONE_DAY;
date.setTimeInMillis(timeCountMills);
Calendar calendar = new Calendar();
calendar.setYear(date.get(java.util.Calendar.YEAR));
calendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
calendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
return calendar;
}
/**
* 是否在日期范围内
*
* @param calendar calendar
* @param delegate delegate
* @return 是否在日期范围内
*/
static boolean isCalendarInRange(Calendar calendar, CalendarViewDelegate delegate) {
return isCalendarInRange(calendar,
delegate.getMinYear(), delegate.getMinYearMonth(), delegate.getMinYearDay(),
delegate.getMaxYear(), delegate.getMaxYearMonth(), delegate.getMaxYearDay());
}
/**
* 是否在日期范围內
*
* @param year year
* @param month month
* @param minYear minYear
* @param minYearMonth minYearMonth
* @param maxYear maxYear
* @param maxYearMonth maxYearMonth
* @return 是否在日期范围內
*/
static boolean isMonthInRange(int year, int month, int minYear, int minYearMonth, int maxYear, int maxYearMonth) {
return !(year < minYear || year > maxYear) &&
!(year == minYear && month < minYearMonth) &&
!(year == maxYear && month > maxYearMonth);
}
/**
* 运算 calendar1 - calendar2
* test Pass
*
* @param calendar1 calendar1
* @param calendar2 calendar2
* @return calendar1 - calendar2
*/
public static int differ(Calendar calendar1, Calendar calendar2) {
if (calendar1 == null) {
return Integer.MIN_VALUE;
}
if (calendar2 == null) {
return Integer.MAX_VALUE;
}
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar1.getYear(), calendar1.getMonth() - 1, calendar1.getDay(), 12, 0, 0);//
long startTimeMills = date.getTimeInMillis();//获得起始时间戳
date.set(calendar2.getYear(), calendar2.getMonth() - 1, calendar2.getDay(), 12, 0, 0);//
long endTimeMills = date.getTimeInMillis();//获得结束时间戳
return (int) ((startTimeMills - endTimeMills) / ONE_DAY);
}
/**
* 比较日期大小
*
* @param minYear minYear
* @param minYearMonth minYearMonth
* @param minYearDay minYearDay
* @param maxYear maxYear
* @param maxYearMonth maxYearMonth
* @param maxYearDay maxYearDay
* @return <0 0 >0
*/
public static int compareTo(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay) {
Calendar first = new Calendar();
first.setYear(minYear);
first.setMonth(minYearMonth);
first.setDay(minYearDay);
Calendar second = new Calendar();
second.setYear(maxYear);
second.setMonth(maxYearMonth);
second.setDay(maxYearDay);
return first.compareTo(second);
}
/**
* 为月视图初始化日历
*
* @param year year
* @param month month
* @param currentDate currentDate
* @param weekStar weekStar
* @return 为月视图初始化日历项
*/
static List<Calendar> initCalendarForMonthView(int year, int month, Calendar currentDate, int weekStar) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(year, month - 1, 1);
int mPreDiff = getMonthViewStartDiff(year, month, weekStar);//获取月视图其实偏移量
int monthDayCount = getMonthDaysCount(year, month);//获取月份真实天数
int preYear, preMonth;
int nextYear, nextMonth;
int size = 42;
List<Calendar> mItems = new ArrayList<>();
int preMonthDaysCount;
if (month == 1) {//如果是1月
preYear = year - 1;
preMonth = 12;
nextYear = year;
nextMonth = month + 1;
preMonthDaysCount = mPreDiff == 0 ? 0 : CalendarUtil.getMonthDaysCount(preYear, preMonth);
} else if (month == 12) {//如果是12月
preYear = year;
preMonth = month - 1;
nextYear = year + 1;
nextMonth = 1;
preMonthDaysCount = mPreDiff == 0 ? 0 : CalendarUtil.getMonthDaysCount(preYear, preMonth);
} else {//平常
preYear = year;
preMonth = month - 1;
nextYear = year;
nextMonth = month + 1;
preMonthDaysCount = mPreDiff == 0 ? 0 : CalendarUtil.getMonthDaysCount(preYear, preMonth);
}
int nextDay = 1;
for (int i = 0; i < size; i++) {
Calendar calendarDate = new Calendar();
if (i < mPreDiff) {
calendarDate.setYear(preYear);
calendarDate.setMonth(preMonth);
calendarDate.setDay(preMonthDaysCount - mPreDiff + i + 1);
} else if (i >= monthDayCount + mPreDiff) {
calendarDate.setYear(nextYear);
calendarDate.setMonth(nextMonth);
calendarDate.setDay(nextDay);
++nextDay;
} else {
calendarDate.setYear(year);
calendarDate.setMonth(month);
calendarDate.setCurrentMonth(true);
calendarDate.setDay(i - mPreDiff + 1);
}
if (calendarDate.equals(currentDate)) {
calendarDate.setCurrentDay(true);
}
LunarCalendar.setupLunarCalendar(calendarDate);
mItems.add(calendarDate);
}
return mItems;
}
static List<Calendar> getWeekCalendars(Calendar calendar, CalendarViewDelegate mDelegate) {
long curTime = calendar.getTimeInMillis();
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(),
calendar.getMonth() - 1,
calendar.getDay(), 12, 0);//
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
int startDiff;
if (mDelegate.getWeekStart() == 1) {
startDiff = week - 1;
} else if (mDelegate.getWeekStart() == 2) {
startDiff = week == 1 ? 6 : week - mDelegate.getWeekStart();
} else {
startDiff = week == 7 ? 0 : week;
}
curTime -= startDiff * ONE_DAY;
java.util.Calendar minCalendar = java.util.Calendar.getInstance();
minCalendar.setTimeInMillis(curTime);
Calendar startCalendar = new Calendar();
startCalendar.setYear(minCalendar.get(java.util.Calendar.YEAR));
startCalendar.setMonth(minCalendar.get(java.util.Calendar.MONTH) + 1);
startCalendar.setDay(minCalendar.get(java.util.Calendar.DAY_OF_MONTH));
return initCalendarForWeekView(startCalendar, mDelegate, mDelegate.getWeekStart());
}
/**
* 生成周视图的7个item
*
* @param calendar 周视图的第一个日子calendar,所以往后推迟6天,生成周视图
* @param mDelegate mDelegate
* @param weekStart weekStart
* @return 生成周视图的7个item
*/
@SuppressWarnings("unused")
static List<Calendar> initCalendarForWeekView(Calendar calendar, CalendarViewDelegate mDelegate, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();//当天时间
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay(), 12, 0);
long curDateMills = date.getTimeInMillis();//生成选择的日期时间戳
//int weekEndDiff = getWeekViewEndDiff(calendar.getYear(), calendar.getMonth(), calendar.getDay(), weekStart);
//weekEndDiff 例如周起始为周日1,当前为2020-04-01,周三,则weekEndDiff为本周结束相差今天三天,weekEndDiff=3
int weekEndDiff = 6;
List<Calendar> mItems = new ArrayList<>();
date.setTimeInMillis(curDateMills);
Calendar selectCalendar = new Calendar();
selectCalendar.setYear(calendar.getYear());
selectCalendar.setMonth(calendar.getMonth());
selectCalendar.setDay(calendar.getDay());
if (selectCalendar.equals(mDelegate.getCurrentDay())) {
selectCalendar.setCurrentDay(true);
}
LunarCalendar.setupLunarCalendar(selectCalendar);
selectCalendar.setCurrentMonth(true);
mItems.add(selectCalendar);
for (int i = 1; i <= weekEndDiff; i++) {
date.setTimeInMillis(curDateMills + i * ONE_DAY);
Calendar calendarDate = new Calendar();
calendarDate.setYear(date.get(java.util.Calendar.YEAR));
calendarDate.setMonth(date.get(java.util.Calendar.MONTH) + 1);
calendarDate.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
if (calendarDate.equals(mDelegate.getCurrentDay())) {
calendarDate.setCurrentDay(true);
}
LunarCalendar.setupLunarCalendar(calendarDate);
calendarDate.setCurrentMonth(true);
mItems.add(calendarDate);
}
return mItems;
}
/**
* 单元测试通过
* 从选定的日期,获取周视图起始偏移量,用来生成周视图布局
*
* @param year year
* @param month month
* @param day day
* @param weekStart 周起始,1,2,7 日 一 六
* @return 获取周视图起始偏移量,用来生成周视图布局
*/
private static int getWeekViewStartDiff(int year, int month, int day, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(year, month - 1, day, 12, 0);//
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == 1) {
return week - 1;
}
if (weekStart == 2) {
return week == 1 ? 6 : week - weekStart;
}
return week == 7 ? 0 : week;
}
/**
* 单元测试通过
* 从选定的日期,获取周视图结束偏移量,用来生成周视图布局
* 为了兼容DST,DST时区可能出现时间偏移1-2小时,从而导致凌晨时候实际获得的日期往前或者往后推移了一天,
* 日历没有时和分的概念,因此把日期的时间强制在12:00,可以避免DST兼容问题
*
* @param year year
* @param month month
* @param day day
* @param weekStart 周起始,1,2,7 日 一 六
* @return 获取周视图结束偏移量,用来生成周视图布局
*/
public static int getWeekViewEndDiff(int year, int month, int day, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(year, month - 1, day, 12, 0);
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == 1) {
return 7 - week;
}
if (weekStart == 2) {
return week == 1 ? 0 : 7 - week + 1;
}
return week == 7 ? 6 : 7 - week - 1;
}
/**
* 从月视图切换获得第一天的日期
* Test Pass 它是100%正确的
*
* @param position position
* @param delegate position
* @return 从月视图切换获得第一天的日期
*/
static Calendar getFirstCalendarFromMonthViewPager(int position, CalendarViewDelegate delegate) {
Calendar calendar = new Calendar();
calendar.setYear((position + delegate.getMinYearMonth() - 1) / 12 + delegate.getMinYear());
calendar.setMonth((position + delegate.getMinYearMonth() - 1) % 12 + 1);
if (delegate.getDefaultCalendarSelectDay() != CalendarViewDelegate.FIRST_DAY_OF_MONTH) {
int monthDays = getMonthDaysCount(calendar.getYear(), calendar.getMonth());
Calendar indexCalendar = delegate.mIndexCalendar;
calendar.setDay(indexCalendar == null || indexCalendar.getDay() == 0 ? 1 :
monthDays < indexCalendar.getDay() ? monthDays : indexCalendar.getDay());
} else {
calendar.setDay(1);
}
if (!isCalendarInRange(calendar, delegate)) {
if (isMinRangeEdge(calendar, delegate)) {
calendar = delegate.getMinRangeCalendar();
} else {
calendar = delegate.getMaxRangeCalendar();
}
}
calendar.setCurrentMonth(calendar.getYear() == delegate.getCurrentDay().getYear() &&
calendar.getMonth() == delegate.getCurrentDay().getMonth());
calendar.setCurrentDay(calendar.equals(delegate.getCurrentDay()));
LunarCalendar.setupLunarCalendar(calendar);
return calendar;
}
/**
* 根据传入的日期获取边界访问日期,要么最大,要么最小
*
* @param calendar calendar
* @param delegate delegate
* @return 获取边界访问日期
*/
static Calendar getRangeEdgeCalendar(Calendar calendar, CalendarViewDelegate delegate) {
if (CalendarUtil.isCalendarInRange(delegate.getCurrentDay(), delegate)
&& delegate.getDefaultCalendarSelectDay() != CalendarViewDelegate.LAST_MONTH_VIEW_SELECT_DAY_IGNORE_CURRENT) {
return delegate.createCurrentDate();
}
if (isCalendarInRange(calendar, delegate)) {
return calendar;
}
Calendar minRangeCalendar = delegate.getMinRangeCalendar();
if (minRangeCalendar.isSameMonth(calendar)) {
return delegate.getMinRangeCalendar();
}
return delegate.getMaxRangeCalendar();
}
/**
* 是否是最小访问边界了
*
* @param calendar calendar
* @return 是否是最小访问边界了
*/
private static boolean isMinRangeEdge(Calendar calendar, CalendarViewDelegate delegate) {
java.util.Calendar c = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
c.setTimeZone(TimeZone.getTimeZone(zone));
}
c.set(delegate.getMinYear(), delegate.getMinYearMonth() - 1, delegate.getMinYearDay(), 12, 0);
long minTime = c.getTimeInMillis();
c.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay(), 12, 0);
long curTime = c.getTimeInMillis();
return curTime < minTime;
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public static Calendar getCalendarByLong(long millis) {
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.setTimeInMillis(millis);
Calendar nextCalendar = new Calendar();
nextCalendar.setYear(date.get(java.util.Calendar.YEAR));
nextCalendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
nextCalendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
return nextCalendar;
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import com.sobot.widget.R;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
/**
* 日历布局
* 各个类使用包权限,避免不必要的public
*/
@SuppressWarnings({"unused"})
public class CalendarView extends FrameLayout {
/**
* 抽取自定义属性
*/
private final CalendarViewDelegate mDelegate;
/**
* 自定义自适应高度的ViewPager
*/
private MonthViewPager mMonthPager;
/**
* 日历周视图
*/
private WeekViewPager mWeekPager;
/**
* 星期栏的线
*/
private View mWeekLine;
/**
* 月份快速选取
*/
private YearViewPager mYearViewPager;
/**
* 星期栏
*/
private WeekBar mWeekBar;
/**
* 日历外部收缩布局
*/
CalendarLayout mParentLayout;
public CalendarView(@NonNull Context context) {
this(context, null);
}
public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mDelegate = new CalendarViewDelegate(context, attrs);
init(context);
}
/**
* 初始化
*
* @param context context
*/
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.sobot_layout_calendar_view, this, true);
FrameLayout frameContent = findViewById(R.id.frameContent);
this.mWeekPager = findViewById(R.id.vp_week);
this.mWeekPager.setup(mDelegate);
try {
Constructor constructor = mDelegate.getWeekBarClass().getConstructor(Context.class);
mWeekBar = (WeekBar) constructor.newInstance(getContext());
} catch (Exception e) {
e.printStackTrace();
}
frameContent.addView(mWeekBar, 2);
mWeekBar.setup(mDelegate);
mWeekBar.onWeekStartChange(mDelegate.getWeekStart());
this.mWeekLine = findViewById(R.id.line);
this.mWeekLine.setBackgroundColor(mDelegate.getWeekLineBackground());
LayoutParams lineParams = (LayoutParams) this.mWeekLine.getLayoutParams();
lineParams.setMargins(mDelegate.getWeekLineMargin(),
mDelegate.getWeekBarHeight(),
mDelegate.getWeekLineMargin(),
0);
this.mWeekLine.setLayoutParams(lineParams);
this.mMonthPager = findViewById(R.id.vp_month);
this.mMonthPager.mWeekPager = mWeekPager;
this.mMonthPager.mWeekBar = mWeekBar;
LayoutParams params = (LayoutParams) this.mMonthPager.getLayoutParams();
params.setMargins(0, mDelegate.getWeekBarHeight() + CalendarUtil.dipToPx(context, 1), 0, 0);
mWeekPager.setLayoutParams(params);
mYearViewPager = findViewById(R.id.selectLayout);
mYearViewPager.setPadding(mDelegate.getYearViewPaddingLeft(), 0, mDelegate.getYearViewPaddingRight(), 0);
mYearViewPager.setBackgroundColor(mDelegate.getYearViewBackground());
mYearViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if (mWeekPager.getVisibility() == VISIBLE) {
return;
}
if (mDelegate.mYearChangeListener != null) {
mDelegate.mYearChangeListener.onYearChange(position + mDelegate.getMinYear());
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
mDelegate.mInnerListener = new OnInnerDateSelectedListener() {
/**
* 月视图选择事件
* @param calendar calendar
* @param isClick 是否是点击
*/
@Override
public void onMonthDateSelected(Calendar calendar, boolean isClick) {
if (calendar.getYear() == mDelegate.getCurrentDay().getYear() &&
calendar.getMonth() == mDelegate.getCurrentDay().getMonth()
&& mMonthPager.getCurrentItem() != mDelegate.mCurrentMonthViewItem) {
return;
}
mDelegate.mIndexCalendar = calendar;
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT || isClick) {
mDelegate.mSelectedCalendar = calendar;
}
mWeekPager.updateSelected(mDelegate.mIndexCalendar, false);
mMonthPager.updateSelected();
if (mWeekBar != null &&
(mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT || isClick)) {
mWeekBar.onDateSelected(calendar, mDelegate.getWeekStart(), isClick);
}
}
/**
* 周视图选择事件
* @param calendar calendar
* @param isClick 是否是点击
*/
@Override
public void onWeekDateSelected(Calendar calendar, boolean isClick) {
mDelegate.mIndexCalendar = calendar;
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT || isClick
|| mDelegate.mIndexCalendar.equals(mDelegate.mSelectedCalendar)) {
mDelegate.mSelectedCalendar = calendar;
}
int y = calendar.getYear() - mDelegate.getMinYear();
int position = 12 * y + mDelegate.mIndexCalendar.getMonth() - mDelegate.getMinYearMonth();
mWeekPager.updateSingleSelect();
mMonthPager.setCurrentItem(position, false);
mMonthPager.updateSelected();
if (mWeekBar != null &&
(mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT
|| isClick
|| mDelegate.mIndexCalendar.equals(mDelegate.mSelectedCalendar))) {
mWeekBar.onDateSelected(calendar, mDelegate.getWeekStart(), isClick);
}
}
};
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
if (isInRange(mDelegate.getCurrentDay())) {
mDelegate.mSelectedCalendar = mDelegate.createCurrentDate();
} else {
mDelegate.mSelectedCalendar = mDelegate.getMinRangeCalendar();
}
} else {
mDelegate.mSelectedCalendar = new Calendar();
}
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, mDelegate.getWeekStart(), false);
mMonthPager.setup(mDelegate);
mMonthPager.setCurrentItem(mDelegate.mCurrentMonthViewItem);
mYearViewPager.setOnMonthSelectedListener(new YearRecyclerView.OnMonthSelectedListener() {
@Override
public void onMonthSelected(int year, int month) {
int position = 12 * (year - mDelegate.getMinYear()) + month - mDelegate.getMinYearMonth();
closeSelectLayout(position);
mDelegate.isShowYearSelectedLayout = false;
}
});
mYearViewPager.setup(mDelegate);
mWeekPager.updateSelected(mDelegate.createCurrentDate(), false);
}
/**
* 设置日期范围
*
* @param minYear 最小年份
* @param minYearMonth 最小年份对应月份
* @param minYearDay 最小年份对应天
* @param maxYear 最大月份
* @param maxYearMonth 最大月份对应月份
* @param maxYearDay 最大月份对应天
*/
public void setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay,String zone) {
if (CalendarUtil.compareTo(minYear, minYearMonth, minYearDay,
maxYear, maxYearMonth, maxYearDay) > 0) {
return;
}
mDelegate.setRange(minYear, minYearMonth, minYearDay,
maxYear, maxYearMonth, maxYearDay);
mWeekPager.notifyDataSetChanged();
mYearViewPager.notifyDataSetChanged();
mMonthPager.notifyDataSetChanged();
if (!isInRange(mDelegate.mSelectedCalendar)) {
mDelegate.mSelectedCalendar = mDelegate.getMinRangeCalendar();
mDelegate.updateSelectCalendarScheme();
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
}
mWeekPager.updateRange();
mMonthPager.updateRange();
mYearViewPager.updateRange();
if(!TextUtils.isEmpty(zone)){
setZone(zone);
}
}
/**
* 获取当天
*
* @return 返回今天
*/
public int getCurDay() {
return mDelegate.getCurrentDay().getDay();
}
/**
* 获取本月
*
* @return 返回本月
*/
public int getCurMonth() {
return mDelegate.getCurrentDay().getMonth();
}
/**
* 获取本年
*
* @return 返回本年
*/
public int getCurYear() {
return mDelegate.getCurrentDay().getYear();
}
/**
* 打开日历年月份快速选择
*
* @param year 年
*/
public void showYearSelectLayout(final int year) {
showSelectLayout(year);
}
/**
* 打开日历年月份快速选择
* 请使用 showYearSelectLayout(final int year) 代替,这个没什么,越来越规范
*
* @param year 年
*/
private void showSelectLayout(final int year) {
if (mParentLayout != null && mParentLayout.mContentView != null) {
if (!mParentLayout.isExpand()) {
mParentLayout.expand();
//return;
}
}
mWeekPager.setVisibility(GONE);
mDelegate.isShowYearSelectedLayout = true;
if (mParentLayout != null) {
mParentLayout.hideContentView();
}
mWeekBar.animate()
.translationY(-mWeekBar.getHeight())
.setInterpolator(new LinearInterpolator())
.setDuration(260)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mWeekBar.setVisibility(GONE);
mYearViewPager.setVisibility(VISIBLE);
mYearViewPager.scrollToYear(year, false);
if (mParentLayout != null && mParentLayout.mContentView != null) {
mParentLayout.expand();
}
}
});
mMonthPager.animate()
.scaleX(0)
.scaleY(0)
.setDuration(260)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mDelegate.mYearViewChangeListener != null) {
mDelegate.mYearViewChangeListener.onYearViewChange(false);
}
}
});
}
/**
* 年月份选择视图是否打开
*
* @return true or false
*/
public boolean isYearSelectLayoutVisible() {
return mYearViewPager.getVisibility() == VISIBLE;
}
/**
* 关闭年月视图选择布局
*/
public void closeYearSelectLayout() {
if (mYearViewPager.getVisibility() == GONE) {
return;
}
int position = 12 * (mDelegate.mSelectedCalendar.getYear() - mDelegate.getMinYear()) +
mDelegate.mSelectedCalendar.getMonth() - mDelegate.getMinYearMonth();
closeSelectLayout(position);
mDelegate.isShowYearSelectedLayout = false;
}
/**
* 关闭日历布局,同时会滚动到指定的位置
*
* @param position 某一年
*/
private void closeSelectLayout(final int position) {
mYearViewPager.setVisibility(GONE);
mWeekBar.setVisibility(VISIBLE);
if (position == mMonthPager.getCurrentItem()) {
if (mDelegate.mCalendarSelectListener != null &&
mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_SINGLE) {
mDelegate.mCalendarSelectListener.onCalendarSelect(mDelegate.mSelectedCalendar, false);
}
} else {
mMonthPager.setCurrentItem(position, false);
}
mWeekBar.animate()
.translationY(0)
.setInterpolator(new LinearInterpolator())
.setDuration(280)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mWeekBar.setVisibility(VISIBLE);
}
});
mMonthPager.animate()
.scaleX(1)
.scaleY(1)
.setDuration(180)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mDelegate.mYearViewChangeListener != null) {
mDelegate.mYearViewChangeListener.onYearViewChange(true);
}
if (mParentLayout != null) {
mParentLayout.showContentView();
if (mParentLayout.isExpand()) {
mMonthPager.setVisibility(VISIBLE);
} else {
mWeekPager.setVisibility(VISIBLE);
mParentLayout.shrink();
}
} else {
mMonthPager.setVisibility(VISIBLE);
}
mMonthPager.clearAnimation();
}
});
}
/**
* 滚动到当前
*/
public void scrollToCurrent() {
scrollToCurrent(false);
}
/**
* 滚动到当前
*
* @param smoothScroll smoothScroll
*/
public void scrollToCurrent(boolean smoothScroll) {
if (!isInRange(mDelegate.getCurrentDay())) {
return;
}
Calendar calendar = mDelegate.createCurrentDate();
if (mDelegate.mCalendarInterceptListener != null &&
mDelegate.mCalendarInterceptListener.onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, false);
return;
}
mDelegate.mSelectedCalendar = mDelegate.createCurrentDate();
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
mDelegate.updateSelectCalendarScheme();
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, mDelegate.getWeekStart(), false);
if (mMonthPager.getVisibility() == VISIBLE) {
mMonthPager.scrollToCurrent(smoothScroll);
mWeekPager.updateSelected(mDelegate.mIndexCalendar, false);
} else {
mWeekPager.scrollToCurrent(smoothScroll);
}
mYearViewPager.scrollToYear(mDelegate.getCurrentDay().getYear(), smoothScroll);
}
/**
* 滚动到下一个月
*/
public void scrollToNext() {
scrollToNext(false);
}
/**
* 滚动到下一个月
*
* @param smoothScroll smoothScroll
*/
public void scrollToNext(boolean smoothScroll) {
if (isYearSelectLayoutVisible()) {
mYearViewPager.setCurrentItem(mYearViewPager.getCurrentItem() + 1, smoothScroll);
} else if (mWeekPager.getVisibility() == VISIBLE) {
mWeekPager.setCurrentItem(mWeekPager.getCurrentItem() + 1, smoothScroll);
} else {
mMonthPager.setCurrentItem(mMonthPager.getCurrentItem() + 1, smoothScroll);
}
}
/**
* 滚动到上一个月
*/
public void scrollToPre() {
scrollToPre(false);
}
/**
* 滚动到上一个月
*
* @param smoothScroll smoothScroll
*/
public void scrollToPre(boolean smoothScroll) {
if (isYearSelectLayoutVisible()) {
mYearViewPager.setCurrentItem(mYearViewPager.getCurrentItem() - 1, smoothScroll);
} else if (mWeekPager.getVisibility() == VISIBLE) {
mWeekPager.setCurrentItem(mWeekPager.getCurrentItem() - 1, smoothScroll);
} else {
mMonthPager.setCurrentItem(mMonthPager.getCurrentItem() - 1, smoothScroll);
}
}
/**
* 滚动到选择的日历
*/
public void scrollToSelectCalendar() {
if (!mDelegate.mSelectedCalendar.isAvailable()) {
return;
}
scrollToCalendar(mDelegate.mSelectedCalendar.getYear(),
mDelegate.mSelectedCalendar.getMonth(),
mDelegate.mSelectedCalendar.getDay(),
false,
true);
}
/**
* 滚动到指定日期
*
* @param year year
* @param month month
* @param day day
*/
public void scrollToCalendar(int year, int month, int day) {
scrollToCalendar(year, month, day, false, true);
}
/**
* 滚动到指定日期
*
* @param year year
* @param month month
* @param day day
* @param smoothScroll smoothScroll
*/
public void scrollToCalendar(int year, int month, int day, boolean smoothScroll) {
scrollToCalendar(year, month, day, smoothScroll, true);
}
/**
* 滚动到指定日期
*
* @param year year
* @param month month
* @param day day
* @param smoothScroll smoothScroll
* @param invokeListener 调用日期事件
*/
public void scrollToCalendar(int year, int month, int day, boolean smoothScroll, boolean invokeListener) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
if (!calendar.isAvailable()) {
return;
}
if (!isInRange(calendar)) {
return;
}
if (mDelegate.mCalendarInterceptListener != null &&
mDelegate.mCalendarInterceptListener.onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, false);
return;
}
if (mWeekPager.getVisibility() == VISIBLE) {
mWeekPager.scrollToCalendar(year, month, day, smoothScroll, invokeListener);
} else {
mMonthPager.scrollToCalendar(year, month, day, smoothScroll, invokeListener);
}
}
/**
* 滚动到某一年
*
* @param year 快速滚动的年份
*/
public void scrollToYear(int year) {
scrollToYear(year, false);
}
/**
* 滚动到某一年
*
* @param year 快速滚动的年份
* @param smoothScroll smoothScroll
*/
public void scrollToYear(int year, boolean smoothScroll) {
if (mYearViewPager.getVisibility() != VISIBLE) {
return;
}
mYearViewPager.scrollToYear(year, smoothScroll);
}
/**
* 设置月视图是否可滚动
*
* @param monthViewScrollable 设置月视图是否可滚动
*/
public final void setMonthViewScrollable(boolean monthViewScrollable) {
mDelegate.setMonthViewScrollable(monthViewScrollable);
}
/**
* 设置周视图是否可滚动
*
* @param weekViewScrollable 设置周视图是否可滚动
*/
public final void setWeekViewScrollable(boolean weekViewScrollable) {
mDelegate.setWeekViewScrollable(weekViewScrollable);
}
/**
* 设置年视图是否可滚动
*
* @param yearViewScrollable 设置年视图是否可滚动
*/
public final void setYearViewScrollable(boolean yearViewScrollable) {
mDelegate.setYearViewScrollable(yearViewScrollable);
}
public final void setDefaultMonthViewSelectDay() {
mDelegate.setDefaultCalendarSelectDay(CalendarViewDelegate.FIRST_DAY_OF_MONTH);
}
public final void setLastMonthViewSelectDay() {
mDelegate.setDefaultCalendarSelectDay(CalendarViewDelegate.LAST_MONTH_VIEW_SELECT_DAY);
}
public final void setLastMonthViewSelectDayIgnoreCurrent() {
mDelegate.setDefaultCalendarSelectDay(CalendarViewDelegate.LAST_MONTH_VIEW_SELECT_DAY_IGNORE_CURRENT);
}
public final void setZone(String zone) {
this.zone = zone;
mDelegate.setZone(zone);
}
private String zone;
/**
* 清除选择范围
*/
public final void clearSelectRange() {
mDelegate.clearSelectRange();
mMonthPager.clearSelectRange();
mWeekPager.clearSelectRange();
}
/**
* 清除单选
*/
public final void clearSingleSelect() {
mDelegate.mSelectedCalendar = new Calendar();
mMonthPager.clearSingleSelect();
mWeekPager.clearSingleSelect();
}
/**
* 清除多选
*/
public final void clearMultiSelect() {
mDelegate.mSelectedCalendars.clear();
mMonthPager.clearMultiSelect();
mWeekPager.clearMultiSelect();
}
/**
* 添加选择
*
* @param calendars calendars
*/
public final void putMultiSelect(Calendar... calendars) {
if (calendars == null || calendars.length == 0) {
return;
}
for (Calendar calendar : calendars) {
if (calendar == null || mDelegate.mSelectedCalendars.containsKey(calendar.toString())) {
continue;
}
mDelegate.mSelectedCalendars.put(calendar.toString(), calendar);
}
update();
}
/**
* 清楚一些多选日期
*
* @param calendars calendars
*/
@SuppressWarnings("RedundantCollectionOperation")
public final void removeMultiSelect(Calendar... calendars) {
if (calendars == null || calendars.length == 0) {
return;
}
for (Calendar calendar : calendars) {
if (calendar == null) {
continue;
}
if (mDelegate.mSelectedCalendars.containsKey(calendar.toString())) {
mDelegate.mSelectedCalendars.remove(calendar.toString());
}
}
update();
}
public final List<Calendar> getMultiSelectCalendars() {
List<Calendar> calendars = new ArrayList<>();
if (mDelegate.mSelectedCalendars.size() == 0) {
return calendars;
}
calendars.addAll(mDelegate.mSelectedCalendars.values());
Collections.sort(calendars);
return calendars;
}
/**
* 获取选中范围
*
* @return return
*/
public final List<Calendar> getSelectCalendarRange() {
return mDelegate.getSelectCalendarRange();
}
/**
* 设置月视图项高度
*
* @param calendarItemHeight MonthView item height
*/
public final void setCalendarItemHeight(int calendarItemHeight) {
if (mDelegate.getCalendarItemHeight() == calendarItemHeight) {
return;
}
mDelegate.setCalendarItemHeight(calendarItemHeight);
mMonthPager.updateItemHeight();
mWeekPager.updateItemHeight();
if (mParentLayout == null) {
return;
}
mParentLayout.updateCalendarItemHeight();
}
/**
* 设置月视图
*
* @param cls MonthView.class
*/
public final void setMonthView(Class<?> cls) {
if (cls == null) {
return;
}
if (mDelegate.getMonthViewClass().equals(cls)) {
return;
}
mDelegate.setMonthViewClass(cls);
mMonthPager.updateMonthViewClass();
}
/**
* 设置周视图
*
* @param cls WeekView.class
*/
public final void setWeekView(Class<?> cls) {
if (cls == null) {
return;
}
if (mDelegate.getWeekBarClass().equals(cls)) {
return;
}
mDelegate.setWeekViewClass(cls);
mWeekPager.updateWeekViewClass();
}
/**
* 设置周栏视图
*
* @param cls WeekBar.class
*/
public final void setWeekBar(Class<?> cls) {
if (cls == null) {
return;
}
if (mDelegate.getWeekBarClass().equals(cls)) {
return;
}
mDelegate.setWeekBarClass(cls);
FrameLayout frameContent = findViewById(R.id.frameContent);
frameContent.removeView(mWeekBar);
try {
Constructor constructor = cls.getConstructor(Context.class);
mWeekBar = (WeekBar) constructor.newInstance(getContext());
} catch (Exception e) {
e.printStackTrace();
}
frameContent.addView(mWeekBar, 2);
mWeekBar.setup(mDelegate);
mWeekBar.onWeekStartChange(mDelegate.getWeekStart());
this.mMonthPager.mWeekBar = mWeekBar;
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, mDelegate.getWeekStart(), false);
}
/**
* 添加日期拦截事件
* 使用此方法,只能基于select_mode = single_mode
* 否则的话,如果标记全部日期为不可点击,那是没有意义的,
* 框架本身也不可能在滑动的过程中全部去判断每个日期的可点击性
*
* @param listener listener
*/
public final void setOnCalendarInterceptListener(OnCalendarInterceptListener listener) {
if (listener == null) {
mDelegate.mCalendarInterceptListener = null;
}
if (listener == null || mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
return;
}
mDelegate.mCalendarInterceptListener = listener;
if (!listener.onCalendarIntercept(mDelegate.mSelectedCalendar)) {
return;
}
mDelegate.mSelectedCalendar = new Calendar();
}
/**
* 点击视图Padding位置的事件
*
* @param listener listener
*/
public final void setOnClickCalendarPaddingListener(OnClickCalendarPaddingListener listener) {
if (listener == null) {
mDelegate.mClickCalendarPaddingListener = null;
}
if (listener == null) {
return;
}
mDelegate.mClickCalendarPaddingListener = listener;
}
/**
* 年份改变事件
*
* @param listener listener
*/
public void setOnYearChangeListener(OnYearChangeListener listener) {
this.mDelegate.mYearChangeListener = listener;
}
/**
* 月份改变事件
*
* @param listener listener
*/
public void setOnMonthChangeListener(OnMonthChangeListener listener) {
this.mDelegate.mMonthChangeListener = listener;
}
/**
* 周视图切换监听
*
* @param listener listener
*/
public void setOnWeekChangeListener(OnWeekChangeListener listener) {
this.mDelegate.mWeekChangeListener = listener;
}
/**
* 日期选择事件
*
* @param listener listener
*/
public void setOnCalendarSelectListener(OnCalendarSelectListener listener) {
this.mDelegate.mCalendarSelectListener = listener;
if (mDelegate.mCalendarSelectListener == null) {
return;
}
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_DEFAULT) {
return;
}
if (!isInRange(mDelegate.mSelectedCalendar)) {
return;
}
mDelegate.updateSelectCalendarScheme();
}
/**
* 日期选择事件
*
* @param listener listener
*/
public final void setOnCalendarRangeSelectListener(OnCalendarRangeSelectListener listener) {
this.mDelegate.mCalendarRangeSelectListener = listener;
}
/**
* 日期多选事件
*
* @param listener listener
*/
public final void setOnCalendarMultiSelectListener(OnCalendarMultiSelectListener listener) {
this.mDelegate.mCalendarMultiSelectListener = listener;
}
/**
* 设置最小范围和最大访问,default:minRange = -1,maxRange = -1 没有限制
*
* @param minRange minRange
* @param maxRange maxRange
*/
public final void setSelectRange(int minRange, int maxRange) {
if (minRange > maxRange) {
return;
}
mDelegate.setSelectRange(minRange, maxRange);
}
public final void setSelectStartCalendar(int startYear, int startMonth, int startDay) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
Calendar startCalendar = new Calendar();
startCalendar.setYear(startYear);
startCalendar.setMonth(startMonth);
startCalendar.setDay(startDay);
setSelectStartCalendar(startCalendar);
}
public final void setSelectStartCalendar(Calendar startCalendar) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
if (startCalendar == null) {
return;
}
if (!isInRange(startCalendar)) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(startCalendar, true);
}
return;
}
if (onCalendarIntercept(startCalendar)) {
if (mDelegate.mCalendarInterceptListener != null) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(startCalendar, false);
}
return;
}
mDelegate.mSelectedEndRangeCalendar = null;
mDelegate.mSelectedStartRangeCalendar = startCalendar;
scrollToCalendar(startCalendar.getYear(), startCalendar.getMonth(), startCalendar.getDay());
}
public final void setSelectEndCalendar(int endYear, int endMonth, int endDay) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
if (mDelegate.mSelectedStartRangeCalendar == null) {
return;
}
Calendar endCalendar = new Calendar();
endCalendar.setYear(endYear);
endCalendar.setMonth(endMonth);
endCalendar.setDay(endDay);
setSelectEndCalendar(endCalendar);
}
public final void setSelectEndCalendar(Calendar endCalendar) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
if (mDelegate.mSelectedStartRangeCalendar == null) {
return;
}
setSelectCalendarRange(mDelegate.mSelectedStartRangeCalendar, endCalendar);
}
/**
* 直接指定选择范围,set select calendar range
*
* @param startYear startYear
* @param startMonth startMonth
* @param startDay startDay
* @param endYear endYear
* @param endMonth endMonth
* @param endDay endDay
*/
public final void setSelectCalendarRange(int startYear, int startMonth, int startDay,
int endYear, int endMonth, int endDay) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
Calendar startCalendar = new Calendar();
startCalendar.setYear(startYear);
startCalendar.setMonth(startMonth);
startCalendar.setDay(startDay);
Calendar endCalendar = new Calendar();
endCalendar.setYear(endYear);
endCalendar.setMonth(endMonth);
endCalendar.setDay(endDay);
setSelectCalendarRange(startCalendar, endCalendar);
}
/**
* 设置选择日期范围
*
* @param startCalendar startCalendar
* @param endCalendar endCalendar
*/
public final void setSelectCalendarRange(Calendar startCalendar, Calendar endCalendar) {
if (mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
if (startCalendar == null || endCalendar == null) {
return;
}
if (onCalendarIntercept(startCalendar)) {
if (mDelegate.mCalendarInterceptListener != null) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(startCalendar, false);
}
return;
}
if (onCalendarIntercept(endCalendar)) {
if (mDelegate.mCalendarInterceptListener != null) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(endCalendar, false);
}
return;
}
int minDiffer = endCalendar.differ(startCalendar);
if (minDiffer < 0) {
return;
}
if (!isInRange(startCalendar) || !isInRange(endCalendar)) {
return;
}
//优先判断各种直接return的情况,减少代码深度
if (mDelegate.getMinSelectRange() != -1 && mDelegate.getMinSelectRange() > minDiffer + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(endCalendar, true);
}
return;
} else if (mDelegate.getMaxSelectRange() != -1 && mDelegate.getMaxSelectRange() <
minDiffer + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(endCalendar, false);
}
return;
}
if (mDelegate.getMinSelectRange() == -1 && minDiffer == 0) {
mDelegate.mSelectedStartRangeCalendar = startCalendar;
mDelegate.mSelectedEndRangeCalendar = null;
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarRangeSelect(startCalendar, false);
}
scrollToCalendar(startCalendar.getYear(), startCalendar.getMonth(), startCalendar.getDay());
return;
}
mDelegate.mSelectedStartRangeCalendar = startCalendar;
mDelegate.mSelectedEndRangeCalendar = endCalendar;
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarRangeSelect(startCalendar, false);
mDelegate.mCalendarRangeSelectListener.onCalendarRangeSelect(endCalendar, true);
}
scrollToCalendar(startCalendar.getYear(), startCalendar.getMonth(), startCalendar.getDay());
}
/**
* 是否拦截日期,此设置续设置mCalendarInterceptListener
*
* @param calendar calendar
* @return 是否拦截日期
*/
protected final boolean onCalendarIntercept(Calendar calendar) {
return mDelegate.mCalendarInterceptListener != null &&
mDelegate.mCalendarInterceptListener.onCalendarIntercept(calendar);
}
/**
* 获得最大多选数量
*
* @return 获得最大多选数量
*/
public final int getMaxMultiSelectSize() {
return mDelegate.getMaxMultiSelectSize();
}
/**
* 设置最大多选数量
*
* @param maxMultiSelectSize 最大多选数量
*/
public final void setMaxMultiSelectSize(int maxMultiSelectSize) {
mDelegate.setMaxMultiSelectSize(maxMultiSelectSize);
}
/**
* 最小选择范围
*
* @return 最小选择范围
*/
public final int getMinSelectRange() {
return mDelegate.getMinSelectRange();
}
/**
* 最大选择范围
*
* @return 最大选择范围
*/
public final int getMaxSelectRange() {
return mDelegate.getMaxSelectRange();
}
/**
* 日期长按事件
*
* @param listener listener
*/
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener) {
this.mDelegate.mCalendarLongClickListener = listener;
}
/**
* 日期长按事件
*
* @param preventLongPressedSelect 防止长按选择日期
* @param listener listener
*/
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener, boolean preventLongPressedSelect) {
this.mDelegate.mCalendarLongClickListener = listener;
this.mDelegate.setPreventLongPressedSelected(preventLongPressedSelect);
}
/**
* 视图改变事件
*
* @param listener listener
*/
public void setOnViewChangeListener(OnViewChangeListener listener) {
this.mDelegate.mViewChangeListener = listener;
}
public void setOnYearViewChangeListener(OnYearViewChangeListener listener) {
this.mDelegate.mYearViewChangeListener = listener;
}
/**
* 保持状态
*
* @return 状态
*/
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
if (mDelegate == null) {
return super.onSaveInstanceState();
}
Bundle bundle = new Bundle();
Parcelable parcelable = super.onSaveInstanceState();
bundle.putParcelable("super", parcelable);
bundle.putSerializable("selected_calendar", mDelegate.mSelectedCalendar);
bundle.putSerializable("index_calendar", mDelegate.mIndexCalendar);
return bundle;
}
/**
* 恢复状态
*
* @param state 状态
*/
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
Parcelable superData = bundle.getParcelable("super");
mDelegate.mSelectedCalendar = (Calendar) bundle.getSerializable("selected_calendar");
mDelegate.mIndexCalendar = (Calendar) bundle.getSerializable("index_calendar");
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(mDelegate.mSelectedCalendar, false);
}
if (mDelegate.mIndexCalendar != null) {
scrollToCalendar(mDelegate.mIndexCalendar.getYear(),
mDelegate.mIndexCalendar.getMonth(),
mDelegate.mIndexCalendar.getDay());
}
update();
super.onRestoreInstanceState(superData);
}
/**
* 初始化时初始化日历卡默认选择位置
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getParent() != null && getParent() instanceof CalendarLayout) {
mParentLayout = (CalendarLayout) getParent();
mMonthPager.mParentLayout = mParentLayout;
mWeekPager.mParentLayout = mParentLayout;
mParentLayout.mWeekBar = mWeekBar;
mParentLayout.setup(mDelegate);
mParentLayout.initStatus();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
if (mDelegate == null ||
!mDelegate.isFullScreenCalendar()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
setCalendarItemHeight((height -
mDelegate.getWeekBarHeight()) / 6);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 标记哪些日期有事件
*
* @param mSchemeDates mSchemeDatesMap 通过自己的需求转换即可
*/
public final void setSchemeDate(Map<String, Calendar> mSchemeDates) {
this.mDelegate.mSchemeDatesMap = mSchemeDates;
this.mDelegate.updateSelectCalendarScheme();
this.mYearViewPager.update();
this.mMonthPager.updateScheme();
this.mWeekPager.updateScheme();
}
/**
* 清空日期标记
*/
public final void clearSchemeDate() {
this.mDelegate.mSchemeDatesMap = null;
this.mDelegate.clearSelectedScheme();
mYearViewPager.update();
mMonthPager.updateScheme();
mWeekPager.updateScheme();
}
/**
* 添加事物标记
*
* @param calendar calendar
*/
public final void addSchemeDate(Calendar calendar) {
if (calendar == null || !calendar.isAvailable()) {
return;
}
if (mDelegate.mSchemeDatesMap == null) {
mDelegate.mSchemeDatesMap = new HashMap<>();
}
mDelegate.mSchemeDatesMap.remove(calendar.toString());
mDelegate.mSchemeDatesMap.put(calendar.toString(), calendar);
this.mDelegate.updateSelectCalendarScheme();
this.mYearViewPager.update();
this.mMonthPager.updateScheme();
this.mWeekPager.updateScheme();
}
/**
* 添加事物标记
*
* @param mSchemeDates mSchemeDates
*/
public final void addSchemeDate(Map<String, Calendar> mSchemeDates) {
if (this.mDelegate == null || mSchemeDates == null || mSchemeDates.size() == 0) {
return;
}
if (this.mDelegate.mSchemeDatesMap == null) {
this.mDelegate.mSchemeDatesMap = new HashMap<>();
}
this.mDelegate.addSchemes(mSchemeDates);
this.mDelegate.updateSelectCalendarScheme();
this.mYearViewPager.update();
this.mMonthPager.updateScheme();
this.mWeekPager.updateScheme();
}
/**
* 移除某天的标记
* 这个API是安全的
*
* @param calendar calendar
*/
public final void removeSchemeDate(Calendar calendar) {
if (calendar == null) {
return;
}
if (mDelegate.mSchemeDatesMap == null || mDelegate.mSchemeDatesMap.size() == 0) {
return;
}
mDelegate.mSchemeDatesMap.remove(calendar.toString());
if (mDelegate.mSelectedCalendar.equals(calendar)) {
mDelegate.clearSelectedScheme();
}
mYearViewPager.update();
mMonthPager.updateScheme();
mWeekPager.updateScheme();
}
/**
* 设置背景色
*
* @param yearViewBackground 年份卡片的背景色
* @param weekBackground 星期栏背景色
* @param lineBg 线的颜色
*/
public void setBackground(int yearViewBackground, int weekBackground, int lineBg) {
mWeekBar.setBackgroundColor(weekBackground);
mYearViewPager.setBackgroundColor(yearViewBackground);
mWeekLine.setBackgroundColor(lineBg);
}
/**
* 设置文本颜色
*
* @param currentDayTextColor 今天字体颜色
* @param curMonthTextColor 当前月份字体颜色
* @param otherMonthColor 其它月份字体颜色
* @param curMonthLunarTextColor 当前月份农历字体颜色
* @param otherMonthLunarTextColor 其它农历字体颜色
*/
public void setTextColor(
int currentDayTextColor,
int curMonthTextColor,
int otherMonthColor,
int curMonthLunarTextColor,
int otherMonthLunarTextColor) {
if (mDelegate == null || mMonthPager == null || mWeekPager == null) {
return;
}
mDelegate.setTextColor(currentDayTextColor, curMonthTextColor,
otherMonthColor, curMonthLunarTextColor, otherMonthLunarTextColor);
mMonthPager.updateStyle();
mWeekPager.updateStyle();
}
/**
* 设置选择的效果
*
* @param selectedThemeColor 选中的标记颜色
* @param selectedTextColor 选中的字体颜色
* @param selectedLunarTextColor 选中的农历字体颜色
*/
public void setSelectedColor(int selectedThemeColor, int selectedTextColor, int selectedLunarTextColor) {
if (mDelegate == null || mMonthPager == null || mWeekPager == null) {
return;
}
mDelegate.setSelectColor(selectedThemeColor, selectedTextColor, selectedLunarTextColor);
mMonthPager.updateStyle();
mWeekPager.updateStyle();
}
/**
* 定制颜色
*
* @param selectedThemeColor 选中的标记颜色
* @param schemeColor 标记背景色
*/
public void setThemeColor(int selectedThemeColor, int schemeColor) {
if (mDelegate == null || mMonthPager == null || mWeekPager == null) {
return;
}
mDelegate.setThemeColor(selectedThemeColor, schemeColor);
mMonthPager.updateStyle();
mWeekPager.updateStyle();
}
/**
* 设置标记的色
*
* @param schemeLunarTextColor 标记农历颜色
* @param schemeColor 标记背景色
* @param schemeTextColor 标记字体颜色
*/
public void setSchemeColor(int schemeColor, int schemeTextColor, int schemeLunarTextColor) {
if (mDelegate == null || mMonthPager == null || mWeekPager == null) {
return;
}
mDelegate.setSchemeColor(schemeColor, schemeTextColor, schemeLunarTextColor);
mMonthPager.updateStyle();
mWeekPager.updateStyle();
}
/**
* 设置年视图的颜色
*
* @param yearViewMonthTextColor 年视图月份颜色
* @param yearViewDayTextColor 年视图天的颜色
* @param yarViewSchemeTextColor 年视图标记颜色
*/
public void setYearViewTextColor(int yearViewMonthTextColor, int yearViewDayTextColor, int yarViewSchemeTextColor) {
if (mDelegate == null || mYearViewPager == null) {
return;
}
mDelegate.setYearViewTextColor(yearViewMonthTextColor, yearViewDayTextColor, yarViewSchemeTextColor);
mYearViewPager.updateStyle();
}
/**
* 设置星期栏的背景和字体颜色
*
* @param weekBackground 背景色
* @param weekTextColor 字体颜色
*/
public void setWeeColor(int weekBackground, int weekTextColor) {
if (mWeekBar == null) {
return;
}
mWeekBar.setBackgroundColor(weekBackground);
mWeekBar.setTextColor(weekTextColor);
}
public void setCalendarPadding(int mCalendarPadding) {
if (mDelegate == null) {
return;
}
mDelegate.setCalendarPadding(mCalendarPadding);
update();
}
public void setCalendarPaddingLeft(int mCalendarPaddingLeft) {
if (mDelegate == null) {
return;
}
mDelegate.setCalendarPaddingLeft(mCalendarPaddingLeft);
update();
}
public void setCalendarPaddingRight(int mCalendarPaddingRight) {
if (mDelegate == null) {
return;
}
mDelegate.setCalendarPaddingRight(mCalendarPaddingRight);
update();
}
/**
* 默认选择模式
*/
public final void setSelectDefaultMode() {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
return;
}
mDelegate.mSelectedCalendar = mDelegate.mIndexCalendar;
mDelegate.setSelectMode(CalendarViewDelegate.SELECT_MODE_DEFAULT);
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, mDelegate.getWeekStart(), false);
mMonthPager.updateDefaultSelect();
mWeekPager.updateDefaultSelect();
}
/**
* 范围模式
*/
public void setSelectRangeMode() {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_RANGE) {
return;
}
mDelegate.setSelectMode(CalendarViewDelegate.SELECT_MODE_RANGE);
clearSelectRange();
}
/**
* 多选模式
*/
public void setSelectMultiMode() {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_MULTI) {
return;
}
mDelegate.setSelectMode(CalendarViewDelegate.SELECT_MODE_MULTI);
clearMultiSelect();
}
/**
* 单选模式
*/
public void setSelectSingleMode() {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_SINGLE) {
return;
}
mDelegate.setSelectMode(CalendarViewDelegate.SELECT_MODE_SINGLE);
mWeekPager.updateSelected();
mMonthPager.updateSelected();
}
/**
* 设置星期日周起始
*/
public void setWeekStarWithSun() {
setWeekStart(CalendarViewDelegate.WEEK_START_WITH_SUN);
}
/**
* 设置星期一周起始
*/
public void setWeekStarWithMon() {
setWeekStart(CalendarViewDelegate.WEEK_START_WITH_MON);
}
/**
* 设置星期六周起始
*/
public void setWeekStarWithSat() {
setWeekStart(CalendarViewDelegate.WEEK_START_WITH_SAT);
}
/**
* 设置周起始
* CalendarViewDelegate.WEEK_START_WITH_SUN
* CalendarViewDelegate.WEEK_START_WITH_MON
* CalendarViewDelegate.WEEK_START_WITH_SAT
*
* @param weekStart 周起始
*/
private void setWeekStart(int weekStart) {
if (weekStart != CalendarViewDelegate.WEEK_START_WITH_SUN &&
weekStart != CalendarViewDelegate.WEEK_START_WITH_MON &&
weekStart != CalendarViewDelegate.WEEK_START_WITH_SAT)
return;
if (weekStart == mDelegate.getWeekStart())
return;
mDelegate.setWeekStart(weekStart);
mWeekBar.onWeekStartChange(weekStart);
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, weekStart, false);
mWeekPager.updateWeekStart();
mMonthPager.updateWeekStart();
mYearViewPager.updateWeekStart();
}
/**
* 是否是单选模式
*
* @return isSingleSelectMode
*/
public boolean isSingleSelectMode() {
return mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_SINGLE;
}
/**
* 设置显示模式为全部
*/
public void setAllMode() {
setShowMode(CalendarViewDelegate.MODE_ALL_MONTH);
}
/**
* 设置显示模式为仅当前月份
*/
public void setOnlyCurrentMode() {
setShowMode(CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH);
}
/**
* 设置显示模式为填充
*/
public void setFixMode() {
setShowMode(CalendarViewDelegate.MODE_FIT_MONTH);
}
/**
* 设置显示模式
* CalendarViewDelegate.MODE_ALL_MONTH
* CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH
* CalendarViewDelegate.MODE_FIT_MONTH
*
* @param mode 月视图显示模式
*/
private void setShowMode(int mode) {
if (mode != CalendarViewDelegate.MODE_ALL_MONTH &&
mode != CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH &&
mode != CalendarViewDelegate.MODE_FIT_MONTH)
return;
if (mDelegate.getMonthViewShowMode() == mode)
return;
mDelegate.setMonthViewShowMode(mode);
mWeekPager.updateShowMode();
mMonthPager.updateShowMode();
mWeekPager.notifyDataSetChanged();
}
/**
* 更新界面,
* 重新设置颜色等都需要调用该方法
*/
public final void update() {
mWeekBar.onWeekStartChange(mDelegate.getWeekStart());
mYearViewPager.update();
mMonthPager.updateScheme();
mWeekPager.updateScheme();
}
/**
* 更新周视图
*/
public void updateWeekBar() {
mWeekBar.onWeekStartChange(mDelegate.getWeekStart());
}
/**
* 更新当前日期
*/
public final void updateCurrentDate() {
if (mDelegate == null || mMonthPager == null || mWeekPager == null) {
return;
}
java.util.Calendar calendar = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
calendar.setTimeZone(TimeZone.getTimeZone(zone));
}
int day = calendar.get(java.util.Calendar.DAY_OF_MONTH);
if (getCurDay() == day) {
return;
}
mDelegate.updateCurrentDay();
mMonthPager.updateCurrentDate();
mWeekPager.updateCurrentDate();
}
/**
* 获取当前周数据
*
* @return 获取当前周数据
*/
public List<Calendar> getCurrentWeekCalendars() {
return mWeekPager.getCurrentWeekCalendars();
}
/**
* 获取当前月份日期
*
* @return return
*/
public List<Calendar> getCurrentMonthCalendars() {
return mMonthPager.getCurrentMonthCalendars();
}
/**
* 获取选择的日期
*
* @return 获取选择的日期
*/
public Calendar getSelectedCalendar() {
return mDelegate.mSelectedCalendar;
}
/**
* 获得最小范围日期
*
* @return 最小范围日期
*/
public Calendar getMinRangeCalendar() {
return mDelegate.getMinRangeCalendar();
}
/**
* 获得最大范围日期
*
* @return 最大范围日期
*/
public Calendar getMaxRangeCalendar() {
return mDelegate.getMaxRangeCalendar();
}
/**
* MonthViewPager
*
* @return 获得月视图
*/
public MonthViewPager getMonthViewPager() {
return mMonthPager;
}
/**
* 获得周视图
*
* @return 获得周视图
*/
public WeekViewPager getWeekViewPager() {
return mWeekPager;
}
/**
* 是否在日期范围内
*
* @param calendar calendar
* @return 是否在日期范围内
*/
protected final boolean isInRange(Calendar calendar) {
return mDelegate != null && CalendarUtil.isCalendarInRange(calendar, mDelegate);
}
/**
* 年份视图切换事件,快速年份切换
*/
public interface OnYearChangeListener {
void onYearChange(int year);
}
/**
* 月份切换事件
*/
public interface OnMonthChangeListener {
void onMonthChange(int year, int month);
}
/**
* 周视图切换事件
*/
public interface OnWeekChangeListener {
void onWeekChange(List<Calendar> weekCalendars);
}
/**
* 内部日期选择,不暴露外部使用
* 主要是用于更新日历CalendarLayout位置
*/
interface OnInnerDateSelectedListener {
/**
* 月视图点击
*
* @param calendar calendar
* @param isClick 是否是点击
*/
void onMonthDateSelected(Calendar calendar, boolean isClick);
/**
* 周视图点击
*
* @param calendar calendar
* @param isClick 是否是点击
*/
void onWeekDateSelected(Calendar calendar, boolean isClick);
}
/**
* 日历范围选择事件
*/
public interface OnCalendarRangeSelectListener {
/**
* 范围选择超出范围越界
*
* @param calendar calendar
*/
void onCalendarSelectOutOfRange(Calendar calendar);
/**
* 选择范围超出范围
*
* @param calendar calendar
* @param isOutOfMinRange 是否小于最小范围,否则为最大范围
*/
void onSelectOutOfRange(Calendar calendar, boolean isOutOfMinRange);
/**
* 日期选择事件
*
* @param calendar calendar
* @param isEnd 是否结束
*/
void onCalendarRangeSelect(Calendar calendar, boolean isEnd);
}
/**
* 日历多选事件
*/
public interface OnCalendarMultiSelectListener {
/**
* 多选超出范围越界
*
* @param calendar calendar
*/
void onCalendarMultiSelectOutOfRange(Calendar calendar);
/**
* 多选超出大小
*
* @param maxSize 最大大小
* @param calendar calendar
*/
void onMultiSelectOutOfSize(Calendar calendar, int maxSize);
/**
* 多选事件
*
* @param calendar calendar
* @param curSize curSize
* @param maxSize maxSize
*/
void onCalendarMultiSelect(Calendar calendar, int curSize, int maxSize);
}
/**
* 日历选择事件
*/
public interface OnCalendarSelectListener {
/**
* 超出范围越界
*
* @param calendar calendar
*/
void onCalendarOutOfRange(Calendar calendar);
/**
* 日期选择事件
*
* @param calendar calendar
* @param isClick isClick
*/
void onCalendarSelect(Calendar calendar, boolean isClick);
}
public interface OnCalendarLongClickListener {
/**
* 超出范围越界
*
* @param calendar calendar
*/
void onCalendarLongClickOutOfRange(Calendar calendar);
/**
* 日期长按事件
*
* @param calendar calendar
*/
void onCalendarLongClick(Calendar calendar);
}
/**
* 视图改变事件
*/
public interface OnViewChangeListener {
/**
* 视图改变事件
*
* @param isMonthView isMonthView是否是月视图
*/
void onViewChange(boolean isMonthView);
}
/**
* 年视图改变事件
*/
public interface OnYearViewChangeListener {
/**
* 年视图变化
*
* @param isClose 是否关闭
*/
void onYearViewChange(boolean isClose);
}
/**
* 拦截日期是否可用事件
*/
public interface OnCalendarInterceptListener {
boolean onCalendarIntercept(Calendar calendar);
void onCalendarInterceptClick(Calendar calendar, boolean isClick);
}
/**
* 点击Padding位置事件
*/
public interface OnClickCalendarPaddingListener {
/**
* 点击Padding位置的事件
*
* @param x x坐标
* @param y y坐标
* @param isMonthView 是否是月视图,不是则为周视图
* @param adjacentCalendar 相邻的日历日期
* @param obj 此处的对象,自行设置
*/
void onClickCalendarPadding(float x, float y, boolean isMonthView,
Calendar adjacentCalendar, Object obj);
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import com.sobot.widget.R;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
/**
* Google规范化的属性委托,
* 代码量多,但是不影响阅读性
*/
final class CalendarViewDelegate {
private String zone;
/**
* 周起始:周日
*/
static final int WEEK_START_WITH_SUN = 1;
/**
* 周起始:周一
*/
static final int WEEK_START_WITH_MON = 2;
/**
* 周起始:周六
*/
static final int WEEK_START_WITH_SAT = 7;
/**
* 默认选择日期1号first_day_of_month
*/
static final int FIRST_DAY_OF_MONTH = 0;
/**
* 跟随上个月last_select_day
*/
static final int LAST_MONTH_VIEW_SELECT_DAY = 1;
/**
* 跟随上个月last_select_day_ignore_current忽视今天
*/
static final int LAST_MONTH_VIEW_SELECT_DAY_IGNORE_CURRENT = 2;
private int mDefaultCalendarSelectDay;
/**
* 周起始
*/
private int mWeekStart;
/**
* 全部显示
*/
static final int MODE_ALL_MONTH = 0;
/**
* 仅显示当前月份
*/
static final int MODE_ONLY_CURRENT_MONTH = 1;
/**
* 自适应显示,不会多出一行,但是会自动填充
*/
static final int MODE_FIT_MONTH = 2;
/**
* 月份显示模式
*/
private int mMonthViewShowMode;
/**
* 默认选择模式
*/
static final int SELECT_MODE_DEFAULT = 0;
/**
* 单选模式
*/
static final int SELECT_MODE_SINGLE = 1;
/**
* 范围选择模式
*/
static final int SELECT_MODE_RANGE = 2;
/**
* 多选模式
*/
static final int SELECT_MODE_MULTI = 3;
/**
* 选择模式
*/
private int mSelectMode;
/**
* 支持转换的最小农历年份
*/
static final int MIN_YEAR = 1900;
/**
* 支持转换的最大农历年份
*/
private static final int MAX_YEAR = 2099;
/**
* 各种字体颜色,看名字知道对应的地方
*/
private int mCurDayTextColor,
mCurDayLunarTextColor,
mWeekTextColor,
mSchemeTextColor,
mSchemeLunarTextColor,
mOtherMonthTextColor,
mCurrentMonthTextColor,
mSelectedTextColor,
mSelectedLunarTextColor,
mCurMonthLunarTextColor,
mOtherMonthLunarTextColor;
private boolean preventLongPressedSelected;
/**
* 年视图一些padding
*/
private int
mYearViewPadding,
mYearViewPaddingLeft,
mYearViewPaddingRight;
/**
* 年视图一些padding
*/
private int
mYearViewMonthPaddingLeft,
mYearViewMonthPaddingRight,
mYearViewMonthPaddingTop,
mYearViewMonthPaddingBottom;
/**
* 日历内部左右padding
*/
private int mCalendarPadding;
/**
* 日历内部左padding
*/
private int mCalendarPaddingLeft;
/**
* 日历内部右padding
*/
private int mCalendarPaddingRight;
/**
* 年视图字体大小
*/
private int mYearViewMonthTextSize,
mYearViewDayTextSize,
mYearViewWeekTextSize;
/**
* 年视图月份高度和周的高度
*/
private int mYearViewMonthHeight,
mYearViewWeekHeight;
/**
* 年视图字体和标记颜色
*/
private int mYearViewMonthTextColor,
mYearViewDayTextColor,
mYearViewSchemeTextColor,
mYearViewSelectTextColor,
mYearViewCurDayTextColor,
mYearViewWeekTextColor;
/**
* 星期栏的背景、线的背景、年份背景
*/
private int mWeekLineBackground,
mYearViewBackground,
mWeekBackground;
/**
* 星期栏Line margin
*/
private int mWeekLineMargin;
/**
* 星期栏字体大小
*/
private int mWeekTextSize;
/**
* 标记的主题色和选中的主题色
*/
private int mSchemeThemeColor, mSelectedThemeColor;
/**
* 自定义的日历路径
*/
private String mMonthViewClassPath;
/**
* 月视图类
*/
private Class<?> mMonthViewClass;
/**
* 自定义周视图路径
*/
private String mWeekViewClassPath;
/**
* 周视图类
*/
private Class<?> mWeekViewClass;
/**
* 自定义年视图路径
*/
private String mYearViewClassPath;
/**
* 周视图类
*/
private Class<?> mYearViewClass;
/**
* 自定义周栏路径
*/
private String mWeekBarClassPath;
/**
* 自定义周栏
*/
private Class<?> mWeekBarClass;
/**
* 年月视图是否打开
*/
boolean isShowYearSelectedLayout;
/**
* 标记文本
*/
private String mSchemeText;
/**
* 最小年份和最大年份
*/
private int mMinYear, mMaxYear;
/**
* 最小年份和最大年份对应最小月份和最大月份
* when you want set 2015-07 to 2017-08
*/
private int mMinYearMonth, mMaxYearMonth;
/**
* 最小年份和最大年份对应最小天和最大天数
* when you want set like 2015-07-08 to 2017-08-30
*/
private int mMinYearDay, mMaxYearDay;
/**
* 日期和农历文本大小
*/
private int mDayTextSize, mLunarTextSize;
/**
* 日历卡的项高度
*/
private int mCalendarItemHeight;
/**
* 是否是全屏日历
*/
private boolean isFullScreenCalendar;
/**
* 星期栏的高度
*/
private int mWeekBarHeight;
/**
* 今天的日子
*/
private Calendar mCurrentDate;
private boolean mMonthViewScrollable,
mWeekViewScrollable,
mYearViewScrollable;
/**
* 当前月份和周视图的item位置
*/
int mCurrentMonthViewItem;
/**
* 标记的日期,数量巨大,请使用这个
*/
Map<String, Calendar> mSchemeDatesMap;
/**
* 点击Padding位置事件
*/
CalendarView.OnClickCalendarPaddingListener mClickCalendarPaddingListener;
/**
* 日期拦截事件
*/
CalendarView.OnCalendarInterceptListener mCalendarInterceptListener;
/**
* 日期选中监听
*/
CalendarView.OnCalendarSelectListener mCalendarSelectListener;
/**
* 范围选择
*/
CalendarView.OnCalendarRangeSelectListener mCalendarRangeSelectListener;
/**
* 多选选择事件
*/
CalendarView.OnCalendarMultiSelectListener mCalendarMultiSelectListener;
/**
* 外部日期长按事件
*/
CalendarView.OnCalendarLongClickListener mCalendarLongClickListener;
/**
* 内部日期切换监听,用于内部更新计算
*/
CalendarView.OnInnerDateSelectedListener mInnerListener;
/**
* 快速年份切换
*/
CalendarView.OnYearChangeListener mYearChangeListener;
/**
* 月份切换事件
*/
CalendarView.OnMonthChangeListener mMonthChangeListener;
/**
* 周视图改变事件
*/
CalendarView.OnWeekChangeListener mWeekChangeListener;
/**
* 视图改变事件
*/
CalendarView.OnViewChangeListener mViewChangeListener;
/**
* 年视图改变事件
*/
CalendarView.OnYearViewChangeListener mYearViewChangeListener;
/**
* 保存选中的日期
*/
Calendar mSelectedCalendar;
/**
* 保存标记位置
*/
Calendar mIndexCalendar;
/**
* 多选日历
*/
Map<String, Calendar> mSelectedCalendars = new HashMap<>();
private int mMaxMultiSelectSize;
/**
* 选择范围日历
*/
Calendar mSelectedStartRangeCalendar, mSelectedEndRangeCalendar;
private int mMinSelectRange, mMaxSelectRange;
CalendarViewDelegate(Context context, @Nullable AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Sobot_CalendarView);
LunarCalendar.init(context);
mCalendarPadding = (int) array.getDimension(R.styleable.Sobot_CalendarView_calendar_padding, 0);
mCalendarPaddingLeft = (int) array.getDimension(R.styleable.Sobot_CalendarView_calendar_padding_left, 0);
mCalendarPaddingRight = (int) array.getDimension(R.styleable.Sobot_CalendarView_calendar_padding_right, 0);
if (mCalendarPadding != 0) {
mCalendarPaddingLeft = mCalendarPadding;
mCalendarPaddingRight = mCalendarPadding;
}
mSchemeTextColor = array.getColor(R.styleable.Sobot_CalendarView_scheme_text_color, 0xFFFFFFFF);
mSchemeLunarTextColor = array.getColor(R.styleable.Sobot_CalendarView_scheme_lunar_text_color, 0xFFe1e1e1);
mSchemeThemeColor = array.getColor(R.styleable.Sobot_CalendarView_scheme_theme_color, 0x50CFCFCF);
mMonthViewClassPath = array.getString(R.styleable.Sobot_CalendarView_month_view);
mYearViewClassPath = array.getString(R.styleable.Sobot_CalendarView_year_view);
mWeekViewClassPath = array.getString(R.styleable.Sobot_CalendarView_week_view);
mWeekBarClassPath = array.getString(R.styleable.Sobot_CalendarView_week_bar_view);
mWeekTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_week_text_size,
CalendarUtil.dipToPx(context, 12));
mWeekBarHeight = (int) array.getDimension(R.styleable.Sobot_CalendarView_week_bar_height,
CalendarUtil.dipToPx(context, 40));
mWeekLineMargin = (int) array.getDimension(R.styleable.Sobot_CalendarView_week_line_margin,
CalendarUtil.dipToPx(context, 0));
mSchemeText = array.getString(R.styleable.Sobot_CalendarView_scheme_text);
if (TextUtils.isEmpty(mSchemeText)) {
mSchemeText = "记";
}
mMonthViewScrollable = array.getBoolean(R.styleable.Sobot_CalendarView_month_view_scrollable, true);
mWeekViewScrollable = array.getBoolean(R.styleable.Sobot_CalendarView_week_view_scrollable, true);
mYearViewScrollable = array.getBoolean(R.styleable.Sobot_CalendarView_year_view_scrollable, true);
mDefaultCalendarSelectDay = array.getInt(R.styleable.Sobot_CalendarView_month_view_auto_select_day,
FIRST_DAY_OF_MONTH);
mMonthViewShowMode = array.getInt(R.styleable.Sobot_CalendarView_month_view_show_mode, MODE_ALL_MONTH);
mWeekStart = array.getInt(R.styleable.Sobot_CalendarView_week_start_with, WEEK_START_WITH_SUN);
mSelectMode = array.getInt(R.styleable.Sobot_CalendarView_select_mode, SELECT_MODE_DEFAULT);
mMaxMultiSelectSize = array.getInt(R.styleable.Sobot_CalendarView_max_multi_select_size, Integer.MAX_VALUE);
mMinSelectRange = array.getInt(R.styleable.Sobot_CalendarView_min_select_range, -1);
mMaxSelectRange = array.getInt(R.styleable.Sobot_CalendarView_max_select_range, -1);
setSelectRange(mMinSelectRange, mMaxSelectRange);
mWeekBackground = array.getColor(R.styleable.Sobot_CalendarView_week_background, Color.WHITE);
mWeekLineBackground = array.getColor(R.styleable.Sobot_CalendarView_week_line_background, Color.TRANSPARENT);
mYearViewBackground = array.getColor(R.styleable.Sobot_CalendarView_year_view_background, Color.WHITE);
mWeekTextColor = array.getColor(R.styleable.Sobot_CalendarView_week_text_color, 0xFF333333);
mCurDayTextColor = array.getColor(R.styleable.Sobot_CalendarView_current_day_text_color, Color.RED);
mCurDayLunarTextColor = array.getColor(R.styleable.Sobot_CalendarView_current_day_lunar_text_color, Color.RED);
mSelectedThemeColor = array.getColor(R.styleable.Sobot_CalendarView_selected_theme_color, 0x50CFCFCF);
mSelectedTextColor = array.getColor(R.styleable.Sobot_CalendarView_selected_text_color, 0xFF111111);
mSelectedLunarTextColor = array.getColor(R.styleable.Sobot_CalendarView_selected_lunar_text_color, 0xFF111111);
mCurrentMonthTextColor = array.getColor(R.styleable.Sobot_CalendarView_current_month_text_color, 0xFF111111);
mOtherMonthTextColor = array.getColor(R.styleable.Sobot_CalendarView_other_month_text_color, 0xFFe1e1e1);
mCurMonthLunarTextColor = array.getColor(R.styleable.Sobot_CalendarView_current_month_lunar_text_color, 0xffe1e1e1);
mOtherMonthLunarTextColor = array.getColor(R.styleable.Sobot_CalendarView_other_month_lunar_text_color, 0xffe1e1e1);
mMinYear = array.getInt(R.styleable.Sobot_CalendarView_min_year, 1971);
mMaxYear = array.getInt(R.styleable.Sobot_CalendarView_max_year, 2055);
mMinYearMonth = array.getInt(R.styleable.Sobot_CalendarView_min_year_month, 1);
mMaxYearMonth = array.getInt(R.styleable.Sobot_CalendarView_max_year_month, 12);
mMinYearDay = array.getInt(R.styleable.Sobot_CalendarView_min_year_day, 1);
mMaxYearDay = array.getInt(R.styleable.Sobot_CalendarView_max_year_day, -1);
mDayTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_day_text_size,
CalendarUtil.dipToPx(context, 16));
mLunarTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_lunar_text_size,
CalendarUtil.dipToPx(context, 10));
mCalendarItemHeight = (int) array.getDimension(R.styleable.Sobot_CalendarView_calendar_height,
CalendarUtil.dipToPx(context, 56));
isFullScreenCalendar = array.getBoolean(R.styleable.Sobot_CalendarView_calendar_match_parent, false);
//年视图相关
mYearViewMonthTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_year_view_month_text_size,
CalendarUtil.dipToPx(context, 18));
mYearViewDayTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_year_view_day_text_size,
CalendarUtil.dipToPx(context, 7));
mYearViewMonthTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_month_text_color, 0xFF111111);
mYearViewDayTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_day_text_color, 0xFF111111);
mYearViewSchemeTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_scheme_color, mSchemeThemeColor);
mYearViewWeekTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_week_text_color, 0xFF333333);
mYearViewCurDayTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_current_day_text_color, mCurDayTextColor);
mYearViewSelectTextColor = array.getColor(R.styleable.Sobot_CalendarView_year_view_select_text_color, 0xFF333333);
mYearViewWeekTextSize = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_year_view_week_text_size,
CalendarUtil.dipToPx(context, 8));
mYearViewMonthHeight = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_year_view_month_height,
CalendarUtil.dipToPx(context, 32));
mYearViewWeekHeight = array.getDimensionPixelSize(R.styleable.Sobot_CalendarView_year_view_week_height,
CalendarUtil.dipToPx(context, 0));
mYearViewPadding = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_padding,
CalendarUtil.dipToPx(context, 12));
mYearViewPaddingLeft = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_padding_left,
CalendarUtil.dipToPx(context, 12));
mYearViewPaddingRight = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_padding_right,
CalendarUtil.dipToPx(context, 12));
if (mYearViewPadding != 0) {
mYearViewPaddingLeft = mYearViewPadding;
mYearViewPaddingRight = mYearViewPadding;
}
mYearViewMonthPaddingTop = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_month_padding_top,
CalendarUtil.dipToPx(context, 4));
mYearViewMonthPaddingBottom = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_month_padding_bottom,
CalendarUtil.dipToPx(context, 4));
mYearViewMonthPaddingLeft = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_month_padding_left,
CalendarUtil.dipToPx(context, 4));
mYearViewMonthPaddingRight = (int) array.getDimension(R.styleable.Sobot_CalendarView_year_view_month_padding_right,
CalendarUtil.dipToPx(context, 4));
if (mMinYear <= MIN_YEAR) mMinYear = MIN_YEAR;
if (mMaxYear >= MAX_YEAR) mMaxYear = MAX_YEAR;
array.recycle();
init();
}
public void setZone (String zone){
this.zone = zone;
}
private void init() {
mCurrentDate = new Calendar();
Date d = new Date();
mCurrentDate.setYear(CalendarUtil.getDate("yyyy", d));
mCurrentDate.setMonth(CalendarUtil.getDate("MM", d));
mCurrentDate.setDay(CalendarUtil.getDate("dd", d));
mCurrentDate.setCurrentDay(true);
LunarCalendar.setupLunarCalendar(mCurrentDate);
setRange(mMinYear, mMinYearMonth, mMaxYear, mMaxYearMonth);
try {
mWeekBarClass = TextUtils.isEmpty(mWeekBarClassPath) ?
mWeekBarClass = WeekBar.class : Class.forName(mWeekBarClassPath);
} catch (Exception e) {
e.printStackTrace();
}
try {
mYearViewClass = TextUtils.isEmpty(mYearViewClassPath) ?
mYearViewClass = DefaultYearView.class : Class.forName(mYearViewClassPath);
} catch (Exception e) {
e.printStackTrace();
}
try {
mMonthViewClass = TextUtils.isEmpty(mMonthViewClassPath) ?
DefaultMonthView.class : Class.forName(mMonthViewClassPath);
} catch (Exception e) {
e.printStackTrace();
}
try {
mWeekViewClass = TextUtils.isEmpty(mWeekViewClassPath) ?
DefaultWeekView.class : Class.forName(mWeekViewClassPath);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setRange(int minYear, int minYearMonth,
int maxYear, int maxYearMonth) {
this.mMinYear = minYear;
this.mMinYearMonth = minYearMonth;
this.mMaxYear = maxYear;
this.mMaxYearMonth = maxYearMonth;
if (this.mMaxYear < mCurrentDate.getYear()) {
this.mMaxYear = mCurrentDate.getYear();
}
if (this.mMaxYearDay == -1) {
this.mMaxYearDay = CalendarUtil.getMonthDaysCount(this.mMaxYear, mMaxYearMonth);
}
int y = mCurrentDate.getYear() - this.mMinYear;
mCurrentMonthViewItem = 12 * y + mCurrentDate.getMonth() - this.mMinYearMonth;
}
void setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay) {
this.mMinYear = minYear;
this.mMinYearMonth = minYearMonth;
this.mMinYearDay = minYearDay;
this.mMaxYear = maxYear;
this.mMaxYearMonth = maxYearMonth;
this.mMaxYearDay = maxYearDay;
// if (this.mMaxYear < mCurrentDate.getYear()) {
// this.mMaxYear = mCurrentDate.getYear();
// }
if (this.mMaxYearDay == -1) {
this.mMaxYearDay = CalendarUtil.getMonthDaysCount(this.mMaxYear, mMaxYearMonth);
}
int y = mCurrentDate.getYear() - this.mMinYear;
mCurrentMonthViewItem = 12 * y + mCurrentDate.getMonth() - this.mMinYearMonth;
}
String getSchemeText() {
return mSchemeText;
}
int getCurDayTextColor() {
return mCurDayTextColor;
}
int getCurDayLunarTextColor() {
return mCurDayLunarTextColor;
}
int getWeekTextColor() {
return mWeekTextColor;
}
int getSchemeTextColor() {
return mSchemeTextColor;
}
int getSchemeLunarTextColor() {
return mSchemeLunarTextColor;
}
int getOtherMonthTextColor() {
return mOtherMonthTextColor;
}
int getCurrentMonthTextColor() {
return mCurrentMonthTextColor;
}
int getSelectedTextColor() {
return mSelectedTextColor;
}
int getSelectedLunarTextColor() {
return mSelectedLunarTextColor;
}
int getCurrentMonthLunarTextColor() {
return mCurMonthLunarTextColor;
}
int getOtherMonthLunarTextColor() {
return mOtherMonthLunarTextColor;
}
int getSchemeThemeColor() {
return mSchemeThemeColor;
}
int getSelectedThemeColor() {
return mSelectedThemeColor;
}
int getWeekBackground() {
return mWeekBackground;
}
int getYearViewBackground() {
return mYearViewBackground;
}
int getWeekLineBackground() {
return mWeekLineBackground;
}
int getWeekLineMargin() {
return mWeekLineMargin;
}
Class<?> getMonthViewClass() {
return mMonthViewClass;
}
Class<?> getWeekViewClass() {
return mWeekViewClass;
}
Class<?> getWeekBarClass() {
return mWeekBarClass;
}
Class<?> getYearViewClass() {
return mYearViewClass;
}
String getYearViewClassPath() {
return mYearViewClassPath;
}
int getWeekBarHeight() {
return mWeekBarHeight;
}
int getMinYear() {
return mMinYear;
}
int getMaxYear() {
return mMaxYear;
}
int getDayTextSize() {
return mDayTextSize;
}
int getLunarTextSize() {
return mLunarTextSize;
}
int getCalendarItemHeight() {
return mCalendarItemHeight;
}
void setCalendarItemHeight(int height) {
mCalendarItemHeight = height;
}
int getMinYearMonth() {
return mMinYearMonth;
}
int getMaxYearMonth() {
return mMaxYearMonth;
}
int getYearViewMonthTextSize() {
return mYearViewMonthTextSize;
}
int getYearViewMonthTextColor() {
return mYearViewMonthTextColor;
}
int getYearViewWeekTextSize() {
return mYearViewWeekTextSize;
}
int getYearViewWeekTextColor() {
return mYearViewWeekTextColor;
}
int getYearViewSelectTextColor() {
return mYearViewSelectTextColor;
}
int getYearViewCurDayTextColor() {
return mYearViewCurDayTextColor;
}
@SuppressWarnings("unused")
int getYearViewPadding() {
return mYearViewPadding;
}
int getYearViewPaddingLeft() {
return mYearViewPaddingLeft;
}
int getYearViewPaddingRight() {
return mYearViewPaddingRight;
}
int getYearViewMonthPaddingLeft() {
return mYearViewMonthPaddingLeft;
}
int getYearViewMonthPaddingRight() {
return mYearViewMonthPaddingRight;
}
int getYearViewMonthPaddingTop() {
return mYearViewMonthPaddingTop;
}
int getYearViewMonthPaddingBottom() {
return mYearViewMonthPaddingBottom;
}
int getYearViewWeekHeight() {
return mYearViewWeekHeight;
}
int getYearViewMonthHeight() {
return mYearViewMonthHeight;
}
int getYearViewDayTextColor() {
return mYearViewDayTextColor;
}
int getYearViewDayTextSize() {
return mYearViewDayTextSize;
}
int getYearViewSchemeTextColor() {
return mYearViewSchemeTextColor;
}
int getMonthViewShowMode() {
return mMonthViewShowMode;
}
void setMonthViewShowMode(int monthViewShowMode) {
this.mMonthViewShowMode = monthViewShowMode;
}
void setTextColor(int curDayTextColor, int curMonthTextColor, int otherMonthTextColor, int curMonthLunarTextColor, int otherMonthLunarTextColor) {
mCurDayTextColor = curDayTextColor;
mOtherMonthTextColor = otherMonthTextColor;
mCurrentMonthTextColor = curMonthTextColor;
mCurMonthLunarTextColor = curMonthLunarTextColor;
mOtherMonthLunarTextColor = otherMonthLunarTextColor;
}
void setSchemeColor(int schemeColor, int schemeTextColor, int schemeLunarTextColor) {
this.mSchemeThemeColor = schemeColor;
this.mSchemeTextColor = schemeTextColor;
this.mSchemeLunarTextColor = schemeLunarTextColor;
}
void setYearViewTextColor(int yearViewMonthTextColor, int yearViewDayTextColor, int yarViewSchemeTextColor) {
this.mYearViewMonthTextColor = yearViewMonthTextColor;
this.mYearViewDayTextColor = yearViewDayTextColor;
this.mYearViewSchemeTextColor = yarViewSchemeTextColor;
}
void setSelectColor(int selectedColor, int selectedTextColor, int selectedLunarTextColor) {
this.mSelectedThemeColor = selectedColor;
this.mSelectedTextColor = selectedTextColor;
this.mSelectedLunarTextColor = selectedLunarTextColor;
}
void setThemeColor(int selectedThemeColor, int schemeColor) {
this.mSelectedThemeColor = selectedThemeColor;
this.mSchemeThemeColor = schemeColor;
}
boolean isMonthViewScrollable() {
return mMonthViewScrollable;
}
boolean isWeekViewScrollable() {
return mWeekViewScrollable;
}
boolean isYearViewScrollable() {
return mYearViewScrollable;
}
void setMonthViewScrollable(boolean monthViewScrollable) {
this.mMonthViewScrollable = monthViewScrollable;
}
void setWeekViewScrollable(boolean weekViewScrollable) {
this.mWeekViewScrollable = weekViewScrollable;
}
void setYearViewScrollable(boolean yearViewScrollable) {
this.mYearViewScrollable = yearViewScrollable;
}
int getWeekStart() {
return mWeekStart;
}
void setWeekStart(int mWeekStart) {
this.mWeekStart = mWeekStart;
}
void setDefaultCalendarSelectDay(int defaultCalendarSelect) {
this.mDefaultCalendarSelectDay = defaultCalendarSelect;
}
int getDefaultCalendarSelectDay() {
return mDefaultCalendarSelectDay;
}
int getWeekTextSize() {
return mWeekTextSize;
}
/**
* 选择模式
*
* @return 选择模式
*/
int getSelectMode() {
return mSelectMode;
}
/**
* 设置选择模式
*
* @param mSelectMode mSelectMode
*/
void setSelectMode(int mSelectMode) {
this.mSelectMode = mSelectMode;
}
int getMinSelectRange() {
return mMinSelectRange;
}
int getMaxSelectRange() {
return mMaxSelectRange;
}
int getMaxMultiSelectSize() {
return mMaxMultiSelectSize;
}
void setMaxMultiSelectSize(int maxMultiSelectSize) {
this.mMaxMultiSelectSize = maxMultiSelectSize;
}
final void setSelectRange(int minRange, int maxRange) {
if (minRange > maxRange && maxRange > 0) {
mMaxSelectRange = minRange;
mMinSelectRange = minRange;
return;
}
if (minRange <= 0) {
mMinSelectRange = -1;
} else {
mMinSelectRange = minRange;
}
if (maxRange <= 0) {
mMaxSelectRange = -1;
} else {
mMaxSelectRange = maxRange;
}
}
Calendar getCurrentDay() {
return mCurrentDate;
}
void updateCurrentDay() {
Date d = new Date();
mCurrentDate.setYear(CalendarUtil.getDate("yyyy", d));
mCurrentDate.setMonth(CalendarUtil.getDate("MM", d));
mCurrentDate.setDay(CalendarUtil.getDate("dd", d));
LunarCalendar.setupLunarCalendar(mCurrentDate);
}
@SuppressWarnings("unused")
int getCalendarPadding() {
return mCalendarPadding;
}
void setCalendarPadding(int mCalendarPadding) {
this.mCalendarPadding = mCalendarPadding;
mCalendarPaddingLeft = mCalendarPadding;
mCalendarPaddingRight = mCalendarPadding;
}
int getCalendarPaddingLeft() {
return mCalendarPaddingLeft;
}
void setCalendarPaddingLeft(int mCalendarPaddingLeft) {
this.mCalendarPaddingLeft = mCalendarPaddingLeft;
}
int getCalendarPaddingRight() {
return mCalendarPaddingRight;
}
void setCalendarPaddingRight(int mCalendarPaddingRight) {
this.mCalendarPaddingRight = mCalendarPaddingRight;
}
void setPreventLongPressedSelected(boolean preventLongPressedSelected) {
this.preventLongPressedSelected = preventLongPressedSelected;
}
void setMonthViewClass(Class<?> monthViewClass) {
this.mMonthViewClass = monthViewClass;
}
void setWeekBarClass(Class<?> weekBarClass) {
this.mWeekBarClass = weekBarClass;
}
void setWeekViewClass(Class<?> weekViewClass) {
this.mWeekViewClass = weekViewClass;
}
boolean isPreventLongPressedSelected() {
return preventLongPressedSelected;
}
void clearSelectedScheme() {
mSelectedCalendar.clearScheme();
}
int getMinYearDay() {
return mMinYearDay;
}
int getMaxYearDay() {
return mMaxYearDay;
}
boolean isFullScreenCalendar() {
return isFullScreenCalendar;
}
final void updateSelectCalendarScheme() {
if (mSchemeDatesMap != null && mSchemeDatesMap.size() > 0) {
String key = mSelectedCalendar.toString();
if (mSchemeDatesMap.containsKey(key)) {
Calendar d = mSchemeDatesMap.get(key);
mSelectedCalendar.mergeScheme(d, getSchemeText());
}
} else {
clearSelectedScheme();
}
}
final void updateCalendarScheme(Calendar targetCalendar) {
if (targetCalendar == null) {
return;
}
if (mSchemeDatesMap == null || mSchemeDatesMap.size() == 0) {
return;
}
String key = targetCalendar.toString();
if (mSchemeDatesMap.containsKey(key)) {
Calendar d = mSchemeDatesMap.get(key);
targetCalendar.mergeScheme(d, getSchemeText());
}
}
Calendar createCurrentDate() {
Calendar calendar = new Calendar();
calendar.setYear(mCurrentDate.getYear());
calendar.setWeek(mCurrentDate.getWeek());
calendar.setMonth(mCurrentDate.getMonth());
calendar.setDay(mCurrentDate.getDay());
calendar.setCurrentDay(true);
LunarCalendar.setupLunarCalendar(calendar);
return calendar;
}
final Calendar getMinRangeCalendar() {
Calendar calendar = new Calendar();
calendar.setYear(mMinYear);
calendar.setMonth(mMinYearMonth);
calendar.setDay(mMinYearDay);
calendar.setCurrentDay(calendar.equals(mCurrentDate));
LunarCalendar.setupLunarCalendar(calendar);
return calendar;
}
@SuppressWarnings("unused")
final Calendar getMaxRangeCalendar() {
Calendar calendar = new Calendar();
calendar.setYear(mMaxYear);
calendar.setMonth(mMaxYearMonth);
calendar.setDay(mMaxYearDay);
calendar.setCurrentDay(calendar.equals(mCurrentDate));
LunarCalendar.setupLunarCalendar(calendar);
return calendar;
}
/**
* 添加事件标记,来自Map
*/
final void addSchemesFromMap(List<Calendar> mItems) {
if (mSchemeDatesMap == null || mSchemeDatesMap.size() == 0) {
return;
}
for (Calendar a : mItems) {
if (mSchemeDatesMap.containsKey(a.toString())) {
Calendar d = mSchemeDatesMap.get(a.toString());
if (d == null) {
continue;
}
a.setScheme(TextUtils.isEmpty(d.getScheme()) ? getSchemeText() : d.getScheme());
a.setSchemeColor(d.getSchemeColor());
a.setSchemes(d.getSchemes());
} else {
a.setScheme("");
a.setSchemeColor(0);
a.setSchemes(null);
}
}
}
/**
* 添加数据
*
* @param mSchemeDates mSchemeDates
*/
final void addSchemes(Map<String, Calendar> mSchemeDates) {
if (mSchemeDates == null || mSchemeDates.size() == 0) {
return;
}
if (this.mSchemeDatesMap == null) {
this.mSchemeDatesMap = new HashMap<>();
}
for (String key : mSchemeDates.keySet()) {
this.mSchemeDatesMap.remove(key);
Calendar calendar = mSchemeDates.get(key);
if (calendar == null) {
continue;
}
this.mSchemeDatesMap.put(key, calendar);
}
}
/**
* 清楚选择
*/
final void clearSelectRange() {
mSelectedStartRangeCalendar = null;
mSelectedEndRangeCalendar = null;
}
/**
* 获得选中范围
*
* @return 选中范围
*/
final List<Calendar> getSelectCalendarRange() {
if (mSelectMode != SELECT_MODE_RANGE) {
return null;
}
List<Calendar> calendars = new ArrayList<>();
if (mSelectedStartRangeCalendar == null ||
mSelectedEndRangeCalendar == null) {
return calendars;
}
final long ONE_DAY = 1000 * 3600 * 24;
java.util.Calendar date = java.util.Calendar.getInstance();
if(!TextUtils.isEmpty(zone)) {
date.setTimeZone(TimeZone.getTimeZone(zone));
}
date.set(mSelectedStartRangeCalendar.getYear(),
mSelectedStartRangeCalendar.getMonth() - 1,
mSelectedStartRangeCalendar.getDay());//
long startTimeMills = date.getTimeInMillis();//获得起始时间戳
date.set(mSelectedEndRangeCalendar.getYear(),
mSelectedEndRangeCalendar.getMonth() - 1,
mSelectedEndRangeCalendar.getDay());//
long endTimeMills = date.getTimeInMillis();
for (long start = startTimeMills; start <= endTimeMills; start += ONE_DAY) {
date.setTimeInMillis(start);
Calendar calendar = new Calendar();
calendar.setYear(date.get(java.util.Calendar.YEAR));
calendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
calendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
LunarCalendar.setupLunarCalendar(calendar);
updateCalendarScheme(calendar);
if (mCalendarInterceptListener != null &&
mCalendarInterceptListener.onCalendarIntercept(calendar)) {
continue;
}
calendars.add(calendar);
}
addSchemesFromMap(calendars);
return calendars;
}
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* https://github.com/huanghaibin-dev/CalendarView
*
* 范围选择月视图
*/
public class CustomRangeMonthView extends RangeMonthView {
private int mRadius;
public CustomRangeMonthView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
if (isSelectedPre) {
if (isSelectedNext) {
canvas.drawRect(x, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
} else {//最后一个,the last
canvas.drawRect(x, cy - mRadius, cx, cy + mRadius, mSelectedPaint);
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
} else {
if(isSelectedNext){
canvas.drawRect(cx, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
}
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
//
}
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
boolean isInRange = isInRange(calendar);
boolean isEnable = !onCalendarIntercept(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* https://github.com/huanghaibin-dev/CalendarView
*
* 范围选择周视图
*/
public class CustomRangeWeekView extends RangeWeekView {
private int mRadius;
public CustomRangeWeekView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
if (isSelectedPre) {
if (isSelectedNext) {
canvas.drawRect(x, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
} else {//最后一个,the last
canvas.drawRect(x, cy - mRadius, cx, cy + mRadius, mSelectedPaint);
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
} else {
if (isSelectedNext) {
canvas.drawRect(cx, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
}
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine;
int cx = x + mItemWidth / 2;
boolean isInRange = isInRange(calendar);
boolean isEnable = !onCalendarIntercept(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.sobot.widget.R;
/**
* 自定义英文栏
*/
public class CustomWeekBar extends WeekBar {
private int mPreSelectedIndex;
public CustomWeekBar(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.sobot_custom_week_bar, this, true);
setBackgroundColor(Color.WHITE);
}
@Override
protected void onDateSelected(Calendar calendar, int weekStart, boolean isClick) {
getChildAt(mPreSelectedIndex).setSelected(false);
int viewIndex = getViewIndexByCalendar(calendar, weekStart);
getChildAt(viewIndex).setSelected(true);
mPreSelectedIndex = viewIndex;
}
/**
* 当周起始发生变化,使用自定义布局需要重写这个方法,避免出问题
*
* @param weekStart 周起始
*/
@Override
protected void onWeekStartChange(int weekStart) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setText(getWeekString(i, weekStart));
}
}
/**
* 或者周文本,这个方法仅供父类使用
* @param index index
* @param weekStart weekStart
* @return 或者周文本
*/
private String getWeekString(int index, int weekStart) {
String[] weeks = getContext().getResources().getStringArray(R.array.week_string_array);
if (weekStart == 1) {
return weeks[index];
}
if (weekStart == 2) {
return weeks[index == 6 ? 0 : index + 1];
}
return weeks[index == 0 ? 6 : index - 1];
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* 默认高仿魅族日历布局
*/
public final class DefaultMonthView extends MonthView {
private Paint mTextPaint = new Paint();
private Paint mSchemeBasicPaint = new Paint();
private float mRadio;
private int mPadding;
private float mSchemeBaseLine;
public DefaultMonthView(Context context) {
super(context);
mTextPaint.setTextSize(CalendarUtil.dipToPx(context, 8));
mTextPaint.setColor(0xffFFFFFF);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xffed5353);
mSchemeBasicPaint.setFakeBoldText(true);
mRadio = CalendarUtil.dipToPx(getContext(), 7);
mPadding = CalendarUtil.dipToPx(getContext(), 4);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + CalendarUtil.dipToPx(getContext(), 1);
}
/**
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme,因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);
canvas.drawText(calendar.getScheme(),
x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
y + mPadding + mSchemeBaseLine, mTextPaint);
}
/**
* 获取字体的宽
* @param text text
* @return return
*/
private float getTextWidth(String text) {
return mTextPaint.measureText(text);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 6;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint : mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* 默认高仿魅族周视图
*/
public final class DefaultWeekView extends WeekView {
private Paint mTextPaint = new Paint();
private Paint mSchemeBasicPaint = new Paint();
private float mRadio;
private int mPadding;
private float mSchemeBaseLine;
public DefaultWeekView(Context context) {
super(context);
mTextPaint.setTextSize(CalendarUtil.dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xffed5353);
mSchemeBasicPaint.setFakeBoldText(true);
mRadio = CalendarUtil.dipToPx(getContext(), 7);
mPadding = CalendarUtil.dipToPx(getContext(), 4);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + CalendarUtil.dipToPx(getContext(), 1);
}
/**
* 如果需要点击Scheme没有效果,则return true
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme,因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, mPadding + mRadio, mRadio, mSchemeBasicPaint);
canvas.drawText(calendar.getScheme(),
x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
mPadding + mSchemeBaseLine, mTextPaint);
}
/**
* 获取字体的宽
* @param text text
* @return return
*/
private float getTextWidth(String text) {
return mTextPaint.measureText(text);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = -mItemHeight / 6;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import com.sobot.widget.R;
/**
* 默认年视图
*/
public class DefaultYearView extends YearView {
private int mTextPadding;
public DefaultYearView(Context context) {
super(context);
mTextPadding = CalendarUtil.dipToPx(context, 3);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawMonth(Canvas canvas, int year, int month, int x, int y, int width, int height) {
String text = getContext()
.getResources()
.getStringArray(R.array.month_string_array)[month - 1];
canvas.drawText(text,
x + mItemWidth / 2 - mTextPadding,
y + mMonthTextBaseLine,
mMonthTextPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawWeek(Canvas canvas, int week, int x, int y, int width, int height) {
String text = getContext().getResources().getStringArray(R.array.year_view_week_string_array)[week];
canvas.drawText(text,
x + width / 2,
y + mWeekTextBaseLine,
mWeekTextPaint);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
hasScheme ? mSchemeTextPaint : mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;
import com.sobot.widget.R;
import java.util.HashMap;
import java.util.Map;
/**
* 农历计算相关
*/
@SuppressWarnings("all")
public final class LunarCalendar {
static void init(Context context) {
if (MONTH_STR != null) {
return;
}
TrunkBranchAnnals.init(context);
SolarTermUtil.init(context);
MONTH_STR = context.getResources().getStringArray(R.array.lunar_first_of_month);
TRADITION_FESTIVAL_STR = context.getResources().getStringArray(R.array.tradition_festival);
DAY_STR = context.getResources().getStringArray(R.array.lunar_str);
SPECIAL_FESTIVAL_STR = context.getResources().getStringArray(R.array.special_festivals);
SOLAR_CALENDAR = context.getResources().getStringArray(R.array.solar_festival);
}
/**
* 农历月份第一天转写
*/
private static String[] MONTH_STR = null;
/**
* 传统农历节日
*/
private static String[] TRADITION_FESTIVAL_STR = null;
/**
* 农历大写
*/
private static String[] DAY_STR = null;
/**
* 特殊节日的数组
*/
private static String[] SPECIAL_FESTIVAL_STR = null;
/**
* 特殊节日、母亲节和父亲节,感恩节等
*/
@SuppressLint("UseSparseArrays")
private static final Map<Integer, String[]> SPECIAL_FESTIVAL = new HashMap<>();
/**
* 公历节日
*/
private static String[] SOLAR_CALENDAR = null;
/**
* 保存每年24节气
*/
@SuppressLint("UseSparseArrays")
private static final Map<Integer, String[]> SOLAR_TERMS = new HashMap<>();
/**
* 返回传统农历节日
*
* @param year 农历年
* @param month 农历月
* @param day 农历日
* @return 返回传统农历节日
*/
private static String getTraditionFestival(int year, int month, int day) {
if (month == 12) {
int count = daysInLunarMonth(year, month);
if (day == count) {
return TRADITION_FESTIVAL_STR[0];//除夕
}
}
String text = getString(month, day);
String festivalStr = "";
for (String festival : TRADITION_FESTIVAL_STR) {
if (festival.contains(text)) {
festivalStr = festival.replace(text, "");
break;
}
}
return festivalStr;
}
/**
* 数字转换为汉字月份
*
* @param month 月
* @param leap 1==闰月
* @return 数字转换为汉字月份
*/
private static String numToChineseMonth(int month, int leap) {
if (leap == 1) {
return "闰" + MONTH_STR[month - 1];
}
return MONTH_STR[month - 1];
}
/**
* 数字转换为农历节日或者日期
*
* @param month 月
* @param day 日
* @param leap 1==闰月
* @return 数字转换为汉字日
*/
private static String numToChinese(int month, int day, int leap) {
if (day == 1) {
return numToChineseMonth(month, leap);
}
return DAY_STR[day - 1];
}
/**
* 用来表示1900年到2099年间农历年份的相关信息,共24位bit的16进制表示,其中:
* 1. 前4位表示该年闰哪个月;
* 2. 5-17位表示农历年份13个月的大小月分布,0表示小,1表示大;
* 3. 最后7位表示农历年首(正月初一)对应的公历日期。
* <p/>
* 以2014年的数据0x955ABF为例说明:
* 1001 0101 0101 1010 1011 1111
* 闰九月 农历正月初一对应公历1月31号
*/
private static final int[] LUNAR_INFO = {
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029
0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079
0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099
0x0d520
};
/**
* 农历 year年month月的总天数,总共有13个月包括闰月
*
* @param year 将要计算的年份
* @param month 将要计算的月份
* @return 传回农历 year年month月的总天数
*/
public static int daysInLunarMonth(int year, int month) {
if ((LUNAR_INFO[year - CalendarViewDelegate.MIN_YEAR] & (0x10000 >> month)) == 0)
return 29;
else
return 30;
}
/**
* 获取公历节日
*
* @param month 公历月份
* @param day 公历日期
* @return 公历节日
*/
private static String gregorianFestival(int month, int day) {
String text = getString(month, day);
String solar = "";
for (String aMSolarCalendar : SOLAR_CALENDAR) {
if (aMSolarCalendar.contains(text)) {
solar = aMSolarCalendar.replace(text, "");
break;
}
}
return solar;
}
private static String getString(int month, int day) {
return (month >= 10 ? String.valueOf(month) : "0" + month) + (day >= 10 ? day : "0" + day);
}
/**
* 返回24节气
*
* @param year 年
* @param month 月
* @param day 日
* @return 返回24节气
*/
private static String getSolarTerm(int year, int month, int day) {
if (!SOLAR_TERMS.containsKey(year)) {
SOLAR_TERMS.put(year, SolarTermUtil.getSolarTerms(year));
}
String[] solarTerm = SOLAR_TERMS.get(year);
String text = year + getString(month, day);
String solar = "";
assert solarTerm != null;
for (String solarTermName : solarTerm) {
if (solarTermName.contains(text)) {
solar = solarTermName.replace(text, "");
break;
}
}
return solar;
}
/**
* 获取农历节日
*
* @param year 年
* @param month 月
* @param day 日
* @return 农历节日
*/
public static String getLunarText(int year, int month, int day) {
String termText = LunarCalendar.getSolarTerm(year, month, day);
String solar = LunarCalendar.gregorianFestival(month, day);
if (!TextUtils.isEmpty(solar))
return solar;
if (!TextUtils.isEmpty(termText))
return termText;
int[] lunar = LunarUtil.solarToLunar(year, month, day);
String festival = getTraditionFestival(lunar[0], lunar[1], lunar[2]);
if (!TextUtils.isEmpty(festival))
return festival;
return LunarCalendar.numToChinese(lunar[1], lunar[2], lunar[3]);
}
/**
* 获取特殊计算方式的节日
* 如:每年五月的第二个星期日为母亲节,六月的第三个星期日为父亲节
* 每年11月第四个星期四定为"感恩节"
*
* @param year year
* @param month month
* @param day day
* @return 获取西方节日
*/
private static String getSpecialFestival(int year, int month, int day) {
if (!SPECIAL_FESTIVAL.containsKey(year)) {
SPECIAL_FESTIVAL.put(year, getSpecialFestivals(year));
}
String[] specialFestivals = SPECIAL_FESTIVAL.get(year);
String text = year + getString(month, day);
String solar = "";
assert specialFestivals != null;
for (String special : specialFestivals) {
if (special.contains(text)) {
solar = special.replace(text, "");
break;
}
}
return solar;
}
/**
* 获取每年的母亲节和父亲节和感恩节
* 特殊计算方式的节日
*
* @param year 年
* @return 获取每年的母亲节和父亲节、感恩节
*/
private static String[] getSpecialFestivals(int year) {
String[] festivals = new String[3];
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(year, 4, 1);
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
int startDiff = 7 - week + 1;
if (startDiff == 7) {
festivals[0] = dateToString(year, 5, startDiff + 1) + SPECIAL_FESTIVAL_STR[0];
} else {
festivals[0] = dateToString(year, 5, startDiff + 7 + 1) + SPECIAL_FESTIVAL_STR[0];
}
date.set(year, 5, 1);
week = date.get(java.util.Calendar.DAY_OF_WEEK);
startDiff = 7 - week + 1;
if (startDiff == 7) {
festivals[1] = dateToString(year, 6, startDiff + 7 + 1) + SPECIAL_FESTIVAL_STR[1];
} else {
festivals[1] = dateToString(year, 6, startDiff + 7 + 7 + 1) + SPECIAL_FESTIVAL_STR[1];
}
date.set(year, 10, 1);
week = date.get(java.util.Calendar.DAY_OF_WEEK);
startDiff = 7 - week + 1;
if (startDiff <= 2) {
festivals[2] = dateToString(year, 11, startDiff + 21 + 5) + SPECIAL_FESTIVAL_STR[2];
} else {
festivals[2] = dateToString(year, 11, startDiff + 14 + 5) + SPECIAL_FESTIVAL_STR[2];
}
return festivals;
}
private static String dateToString(int year, int month, int day) {
return year + getString(month, day);
}
/**
* 初始化各种农历、节日
*
* @param calendar calendar
*/
public static void setupLunarCalendar(Calendar calendar) {
int year = calendar.getYear();
int month = calendar.getMonth();
int day = calendar.getDay();
calendar.setWeekend(CalendarUtil.isWeekend(calendar));
calendar.setWeek(CalendarUtil.getWeekFormCalendar(calendar));
Calendar lunarCalendar = new Calendar();
calendar.setLunarCalendar(lunarCalendar);
int[] lunar = LunarUtil.solarToLunar(year, month, day);
lunarCalendar.setYear(lunar[0]);
lunarCalendar.setMonth(lunar[1]);
lunarCalendar.setDay(lunar[2]);
calendar.setLeapYear(CalendarUtil.isLeapYear(year));
if (lunar[3] == 1) {//如果是闰月
calendar.setLeapMonth(lunar[1]);
lunarCalendar.setLeapMonth(lunar[1]);
}
String solarTerm = LunarCalendar.getSolarTerm(year, month, day);
String gregorian = LunarCalendar.gregorianFestival(month, day);
String festival = getTraditionFestival(lunar[0], lunar[1], lunar[2]);
String lunarText = LunarCalendar.numToChinese(lunar[1], lunar[2], lunar[3]);
if (TextUtils.isEmpty(gregorian)) {
gregorian = getSpecialFestival(year, month, day);
}
calendar.setSolarTerm(solarTerm);
calendar.setGregorianFestival(gregorian);
calendar.setTraditionFestival(festival);
lunarCalendar.setTraditionFestival(festival);
lunarCalendar.setSolarTerm(solarTerm);
if (!TextUtils.isEmpty(solarTerm)) {
calendar.setLunar(solarTerm);
} else if (!TextUtils.isEmpty(gregorian)) {
calendar.setLunar(gregorian);
} else if (!TextUtils.isEmpty(festival)) {
calendar.setLunar(festival);
} else {
calendar.setLunar(lunarText);
}
lunarCalendar.setLunar(lunarText);
}
/**
* 获取农历节日
*
* @param calendar calendar
* @return 获取农历节日
*/
public static String getLunarText(Calendar calendar) {
return getLunarText(calendar.getYear(), calendar.getMonth(), calendar.getDay());
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
/**
* 农历计算方法
*/
public final class LunarUtil {
private static int[] LUNAR_MONTH_DAYS = {1887, 0x1694, 0x16aa, 0x4ad5, 0xab6, 0xc4b7, 0x4ae, 0xa56, 0xb52a, 0x1d2a,
0xd54, 0x75aa, 0x156a, 0x1096d, 0x95c, 0x14ae, 0xaa4d, 0x1a4c, 0x1b2a, 0x8d55, 0xad4, 0x135a, 0x495d, 0x95c,
0xd49b, 0x149a, 0x1a4a, 0xbaa5, 0x16a8, 0x1ad4, 0x52da, 0x12b6, 0xe937, 0x92e, 0x1496, 0xb64b, 0xd4a, 0xda8,
0x95b5, 0x56c, 0x12ae, 0x492f, 0x92e, 0xcc96, 0x1a94, 0x1d4a, 0xada9, 0xb5a, 0x56c, 0x726e, 0x125c, 0xf92d,
0x192a, 0x1a94, 0xdb4a, 0x16aa, 0xad4, 0x955b, 0x4ba, 0x125a, 0x592b, 0x152a, 0xf695, 0xd94, 0x16aa, 0xaab5,
0x9b4, 0x14b6, 0x6a57, 0xa56, 0x1152a, 0x1d2a, 0xd54, 0xd5aa, 0x156a, 0x96c, 0x94ae, 0x14ae, 0xa4c, 0x7d26,
0x1b2a, 0xeb55, 0xad4, 0x12da, 0xa95d, 0x95a, 0x149a, 0x9a4d, 0x1a4a, 0x11aa5, 0x16a8, 0x16d4, 0xd2da,
0x12b6, 0x936, 0x9497, 0x1496, 0x1564b, 0xd4a, 0xda8, 0xd5b4, 0x156c, 0x12ae, 0xa92f, 0x92e, 0xc96, 0x6d4a,
0x1d4a, 0x10d65, 0xb58, 0x156c, 0xb26d, 0x125c, 0x192c, 0x9a95, 0x1a94, 0x1b4a, 0x4b55, 0xad4, 0xf55b,
0x4ba, 0x125a, 0xb92b, 0x152a, 0x1694, 0x96aa, 0x15aa, 0x12ab5, 0x974, 0x14b6, 0xca57, 0xa56, 0x1526,
0x8e95, 0xd54, 0x15aa, 0x49b5, 0x96c, 0xd4ae, 0x149c, 0x1a4c, 0xbd26, 0x1aa6, 0xb54, 0x6d6a, 0x12da,
0x1695d, 0x95a, 0x149a, 0xda4b, 0x1a4a, 0x1aa4, 0xbb54, 0x16b4, 0xada, 0x495b, 0x936, 0xf497, 0x1496,
0x154a, 0xb6a5, 0xda4, 0x15b4, 0x6ab6, 0x126e, 0x1092f, 0x92e, 0xc96, 0xcd4a, 0x1d4a, 0xd64, 0x956c, 0x155c,
0x125c, 0x792e, 0x192c, 0xfa95, 0x1a94, 0x1b4a, 0xab55, 0xad4, 0x14da, 0x8a5d, 0xa5a, 0x1152b, 0x152a,
0x1694, 0xd6aa, 0x15aa, 0xab4, 0x94ba, 0x14b6, 0xa56, 0x7527, 0xd26, 0xee53, 0xd54, 0x15aa, 0xa9b5, 0x96c,
0x14ae, 0x8a4e, 0x1a4c, 0x11d26, 0x1aa4, 0x1b54, 0xcd6a, 0xada, 0x95c, 0x949d, 0x149a, 0x1a2a, 0x5b25,
0x1aa4, 0xfb52, 0x16b4, 0xaba, 0xa95b, 0x936, 0x1496, 0x9a4b, 0x154a, 0x136a5, 0xda4, 0x15ac};
private static int[] SOLAR = {1887, 0xec04c, 0xec23f, 0xec435, 0xec649, 0xec83e, 0xeca51, 0xecc46, 0xece3a,
0xed04d, 0xed242, 0xed436, 0xed64a, 0xed83f, 0xeda53, 0xedc48, 0xede3d, 0xee050, 0xee244, 0xee439, 0xee64d,
0xee842, 0xeea36, 0xeec4a, 0xeee3e, 0xef052, 0xef246, 0xef43a, 0xef64e, 0xef843, 0xefa37, 0xefc4b, 0xefe41,
0xf0054, 0xf0248, 0xf043c, 0xf0650, 0xf0845, 0xf0a38, 0xf0c4d, 0xf0e42, 0xf1037, 0xf124a, 0xf143e, 0xf1651,
0xf1846, 0xf1a3a, 0xf1c4e, 0xf1e44, 0xf2038, 0xf224b, 0xf243f, 0xf2653, 0xf2848, 0xf2a3b, 0xf2c4f, 0xf2e45,
0xf3039, 0xf324d, 0xf3442, 0xf3636, 0xf384a, 0xf3a3d, 0xf3c51, 0xf3e46, 0xf403b, 0xf424e, 0xf4443, 0xf4638,
0xf484c, 0xf4a3f, 0xf4c52, 0xf4e48, 0xf503c, 0xf524f, 0xf5445, 0xf5639, 0xf584d, 0xf5a42, 0xf5c35, 0xf5e49,
0xf603e, 0xf6251, 0xf6446, 0xf663b, 0xf684f, 0xf6a43, 0xf6c37, 0xf6e4b, 0xf703f, 0xf7252, 0xf7447, 0xf763c,
0xf7850, 0xf7a45, 0xf7c39, 0xf7e4d, 0xf8042, 0xf8254, 0xf8449, 0xf863d, 0xf8851, 0xf8a46, 0xf8c3b, 0xf8e4f,
0xf9044, 0xf9237, 0xf944a, 0xf963f, 0xf9853, 0xf9a47, 0xf9c3c, 0xf9e50, 0xfa045, 0xfa238, 0xfa44c, 0xfa641,
0xfa836, 0xfaa49, 0xfac3d, 0xfae52, 0xfb047, 0xfb23a, 0xfb44e, 0xfb643, 0xfb837, 0xfba4a, 0xfbc3f, 0xfbe53,
0xfc048, 0xfc23c, 0xfc450, 0xfc645, 0xfc839, 0xfca4c, 0xfcc41, 0xfce36, 0xfd04a, 0xfd23d, 0xfd451, 0xfd646,
0xfd83a, 0xfda4d, 0xfdc43, 0xfde37, 0xfe04b, 0xfe23f, 0xfe453, 0xfe648, 0xfe83c, 0xfea4f, 0xfec44, 0xfee38,
0xff04c, 0xff241, 0xff436, 0xff64a, 0xff83e, 0xffa51, 0xffc46, 0xffe3a, 0x10004e, 0x100242, 0x100437,
0x10064b, 0x100841, 0x100a53, 0x100c48, 0x100e3c, 0x10104f, 0x101244, 0x101438, 0x10164c, 0x101842,
0x101a35, 0x101c49, 0x101e3d, 0x102051, 0x102245, 0x10243a, 0x10264e, 0x102843, 0x102a37, 0x102c4b,
0x102e3f, 0x103053, 0x103247, 0x10343b, 0x10364f, 0x103845, 0x103a38, 0x103c4c, 0x103e42, 0x104036,
0x104249, 0x10443d, 0x104651, 0x104846, 0x104a3a, 0x104c4e, 0x104e43, 0x105038, 0x10524a, 0x10543e,
0x105652, 0x105847, 0x105a3b, 0x105c4f, 0x105e45, 0x106039, 0x10624c, 0x106441, 0x106635, 0x106849,
0x106a3d, 0x106c51, 0x106e47, 0x10703c, 0x10724f, 0x107444, 0x107638, 0x10784c, 0x107a3f, 0x107c53,
0x107e48};
private static int getBitInt(int data, int length, int shift) {
return (data & (((1 << length) - 1) << shift)) >> shift;
}
private static long solarToInt(int y, int m, int d) {
m = (m + 9) % 12;
y = y - m / 10;
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (d - 1);
}
private static int[] solarFromInt(long g) {
long y = (10000 * g + 14780) / 3652425;
long ddd = g - (365 * y + y / 4 - y / 100 + y / 400);
if (ddd < 0) {
y--;
ddd = g - (365 * y + y / 4 - y / 100 + y / 400);
}
long mi = (100 * ddd + 52) / 3060;
long mm = (mi + 2) % 12 + 1;
y = y + (mi + 2) / 12;
long dd = ddd - (mi * 306 + 5) / 10 + 1;
int[] solar = new int[4];
solar[0] = (int) y;
solar[1] = (int) mm;
solar[2] = (int) dd;
return solar;
}
/**
* 公历转农历 Solar To Lunar
*
* @param year 公历年
* @param month 公历月
* @param day 公历日
* @return [0]农历年 [1]农历月 [2]农历日 [3]是否闰月 0 false : 1 true
*/
@SuppressWarnings("all")
public static int[] solarToLunar(int year, int month, int day) {
int[] lunarInt = new int[4];
int index = year - SOLAR[0];
int data = (year << 9) | (month << 5) | (day);
int solar11;
if (SOLAR[index] > data) {
index--;
}
solar11 = SOLAR[index];
int y = getBitInt(solar11, 12, 9);
int m = getBitInt(solar11, 4, 5);
int d = getBitInt(solar11, 5, 0);
long offset = solarToInt(year, month, day) - solarToInt(y, m, d);
int days = LUNAR_MONTH_DAYS[index];
int leap = getBitInt(days, 4, 13);
int lunarY = index + SOLAR[0];
int lunarM = 1;
int lunarD;
offset += 1;
for (int i = 0; i < 13; i++) {
int dm = getBitInt(days, 1, 12 - i) == 1 ? 30 : 29;
if (offset > dm) {
lunarM++;
offset -= dm;
} else {
break;
}
}
lunarD = (int) (offset);
lunarInt[0] = lunarY;
lunarInt[1] = lunarM;
lunarInt[3] = 0;
if (leap != 0 && lunarM > leap) {
lunarInt[1] = lunarM - 1;
if (lunarM == leap + 1) {
lunarInt[3] = 1;
}
}
lunarInt[2] = lunarD;
return lunarInt;
}
/**
* 农历转公历
*
* @param lunarYear 农历年
* @param lunarMonth 农历月
* @param lunarDay 农历天
* @param isLeap 是否是闰年 0 false : 1 true
* @return [0]新历年 [1]新历月 [2]新历日 [3]是否闰月 0 false : 1 true
*/
@SuppressWarnings("unused")
public static int[] lunarToSolar(int lunarYear, int lunarMonth, int lunarDay, boolean isLeap) {
int days = LUNAR_MONTH_DAYS[lunarYear - LUNAR_MONTH_DAYS[0]];
int leap = getBitInt(days, 4, 13);
int offset = 0;
int loop = leap;
if (!isLeap) {
if (lunarMonth <= leap || leap == 0) {
loop = lunarMonth - 1;
} else {
loop = lunarMonth;
}
}
for (int i = 0; i < loop; i++) {
offset += getBitInt(days, 1, 12 - i) == 1 ? 30 : 29;
}
offset += lunarDay;
int solar11 = SOLAR[lunarYear - SOLAR[0]];
int y = getBitInt(solar11, 12, 9);
int m = getBitInt(solar11, 4, 5);
int d = getBitInt(solar11, 5, 0);
return solarFromInt(solarToInt(y, m, d) + offset - 1);
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import java.io.Serializable;
@SuppressWarnings("unused")
final class Month implements Serializable {
private int diff;//日期偏移
private int count;
private int month;
private int year;
int getDiff() {
return diff;
}
void setDiff(int diff) {
this.diff = diff;
}
int getCount() {
return count;
}
void setCount(int count) {
this.count = count;
}
int getMonth() {
return month;
}
void setMonth(int month) {
this.month = month;
}
int getYear() {
return year;
}
void setYear(int year) {
this.year = year;
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 月视图基础控件,可自由继承实现
*/
public abstract class MonthView extends BaseMonthView {
public MonthView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
if (mLineCount == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
int count = mLineCount * 7;
int d = 0;
for (int i = 0; i < mLineCount; i++) {
for (int j = 0; j < 7; j++) {
Calendar calendar = mItems.get(d);
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH) {
if (d > mItems.size() - mNextDiff) {
return;
}
if (!calendar.isCurrentMonth()) {
++d;
continue;
}
} else if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_FIT_MONTH) {
if (d >= count) {
return;
}
}
draw(canvas, calendar, i, j, d);
++d;
}
}
}
/**
* 开始绘制
*
* @param canvas canvas
* @param calendar 对应日历
* @param i i
* @param j j
* @param d d
*/
private void draw(Canvas canvas, Calendar calendar, int i, int j, int d) {
int x = j * mItemWidth + mDelegate.getCalendarPaddingLeft();
int y = i * mItemHeight;
onLoopStart(x, y);
boolean isSelected = d == mCurrentItem;
boolean hasScheme = calendar.hasScheme();
if (hasScheme) {
//标记的日子
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, y, true);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, y);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, y, false);
}
}
onDrawText(canvas, calendar, x, y, hasScheme, isSelected);
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH &&
!calendar.isCurrentMonth()) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarOutOfRange(calendar);
}
return;
}
mCurrentItem = mItems.indexOf(calendar);
if (!calendar.isCurrentMonth() && mMonthViewPager != null) {
int cur = mMonthViewPager.getCurrentItem();
int position = mCurrentItem < 7 ? cur - 1 : cur + 1;
mMonthViewPager.setCurrentItem(position);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, true);
}
if (mParentLayout != null) {
if (calendar.isCurrentMonth()) {
mParentLayout.updateSelectPosition(mItems.indexOf(calendar));
} else {
mParentLayout.updateSelectWeek(CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart()));
}
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, true);
}
}
@Override
public boolean onLongClick(View v) {
if (mDelegate.mCalendarLongClickListener == null)
return false;
if (!isClick) {
return false;
}
Calendar calendar = getIndex();
if (calendar == null) {
return false;
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH &&
!calendar.isCurrentMonth()) {
return false;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return false;
}
boolean isCalendarInRange = isInRange(calendar);
if (!isCalendarInRange) {
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClickOutOfRange(calendar);
}
return true;
}
if (mDelegate.isPreventLongPressedSelected()) {
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClick(calendar);
}
return true;
}
mCurrentItem = mItems.indexOf(calendar);
if (!calendar.isCurrentMonth() && mMonthViewPager != null) {
int cur = mMonthViewPager.getCurrentItem();
int position = mCurrentItem < 7 ? cur - 1 : cur + 1;
mMonthViewPager.setCurrentItem(position);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, true);
}
if (mParentLayout != null) {
if (calendar.isCurrentMonth()) {
mParentLayout.updateSelectPosition(mItems.indexOf(calendar));
} else {
mParentLayout.updateSelectWeek(CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart()));
}
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, true);
}
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClick(calendar);
}
invalidate();
return true;
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return 是否绘制onDrawScheme,true or false
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme);
/**
* 绘制标记的日期,这里可以是背景色,标记色什么的
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import java.lang.reflect.Constructor;
import java.util.List;
/**
* 月份切换ViewPager,自定义适应高度
*/
public final class MonthViewPager extends ViewPager {
private boolean isUpdateMonthView;
private int mMonthCount;
private CalendarViewDelegate mDelegate;
private int mNextViewHeight, mPreViewHeight, mCurrentViewHeight;
CalendarLayout mParentLayout;
WeekViewPager mWeekPager;
WeekBar mWeekBar;
/**
* 是否使用滚动到某一天
*/
private boolean isUsingScrollToCalendar = false;
public MonthViewPager(Context context) {
this(context, null);
}
public MonthViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 初始化
*
* @param delegate delegate
*/
void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
updateMonthViewHeight(mDelegate.getCurrentDay().getYear(),
mDelegate.getCurrentDay().getMonth());
ViewGroup.LayoutParams params = getLayoutParams();
params.height = mCurrentViewHeight;
setLayoutParams(params);
init();
}
/**
* 初始化
*/
private void init() {
mMonthCount = 12 * (mDelegate.getMaxYear() - mDelegate.getMinYear())
- mDelegate.getMinYearMonth() + 1 +
mDelegate.getMaxYearMonth();
setAdapter(new MonthViewPagerAdapter());
addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {
return;
}
int height;
if (position < getCurrentItem()) {//右滑-1
height = (int) ((mPreViewHeight)
* (1 - positionOffset) +
mCurrentViewHeight
* positionOffset);
} else {//左滑+!
height = (int) ((mCurrentViewHeight)
* (1 - positionOffset) +
(mNextViewHeight)
* positionOffset);
}
ViewGroup.LayoutParams params = getLayoutParams();
params.height = height;
setLayoutParams(params);
}
@Override
public void onPageSelected(int position) {
Calendar calendar = CalendarUtil.getFirstCalendarFromMonthViewPager(position, mDelegate);
if (getVisibility() == VISIBLE) {
if (!mDelegate.isShowYearSelectedLayout &&
mDelegate.mIndexCalendar != null &&
calendar.getYear() != mDelegate.mIndexCalendar.getYear() &&
mDelegate.mYearChangeListener != null) {
mDelegate.mYearChangeListener.onYearChange(calendar.getYear());
}
mDelegate.mIndexCalendar = calendar;
}
//月份改变事件
if (mDelegate.mMonthChangeListener != null) {
mDelegate.mMonthChangeListener.onMonthChange(calendar.getYear(), calendar.getMonth());
}
//周视图显示的时候就需要动态改变月视图高度
if (mWeekPager.getVisibility() == VISIBLE) {
updateMonthViewHeight(calendar.getYear(), calendar.getMonth());
return;
}
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
if (!calendar.isCurrentMonth()) {
mDelegate.mSelectedCalendar = calendar;
} else {
mDelegate.mSelectedCalendar = CalendarUtil.getRangeEdgeCalendar(calendar, mDelegate);
}
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
} else {
if (mDelegate.mSelectedStartRangeCalendar != null &&
mDelegate.mSelectedStartRangeCalendar.isSameMonth(mDelegate.mIndexCalendar)) {
mDelegate.mIndexCalendar = mDelegate.mSelectedStartRangeCalendar;
} else {
if (calendar.isSameMonth(mDelegate.mSelectedCalendar)) {
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
}
}
}
mDelegate.updateSelectCalendarScheme();
if (!isUsingScrollToCalendar && mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
mWeekBar.onDateSelected(mDelegate.mSelectedCalendar, mDelegate.getWeekStart(), false);
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(mDelegate.mSelectedCalendar, false);
}
}
BaseMonthView view = findViewWithTag(position);
if (view != null) {
int index = view.getSelectedIndex(mDelegate.mIndexCalendar);
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
view.mCurrentItem = index;
}
if (index >= 0 && mParentLayout != null) {
mParentLayout.updateSelectPosition(index);
}
view.invalidate();
}
mWeekPager.updateSelected(mDelegate.mIndexCalendar, false);
updateMonthViewHeight(calendar.getYear(), calendar.getMonth());
isUsingScrollToCalendar = false;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* 更新月视图的高度
*
* @param year year
* @param month month
*/
private void updateMonthViewHeight(int year, int month) {
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {//非动态高度就不需要了
mCurrentViewHeight = 6 * mDelegate.getCalendarItemHeight();
ViewGroup.LayoutParams params = getLayoutParams();
params.height = mCurrentViewHeight;
return;
}
if (mParentLayout != null) {
if (getVisibility() != VISIBLE) {//如果已经显示周视图,则需要动态改变月视图高度,否则显示就有bug
ViewGroup.LayoutParams params = getLayoutParams();
params.height = CalendarUtil.getMonthViewHeight(year, month,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
setLayoutParams(params);
}
mParentLayout.updateContentViewTranslateY();
}
mCurrentViewHeight = CalendarUtil.getMonthViewHeight(year, month,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
if (month == 1) {
mPreViewHeight = CalendarUtil.getMonthViewHeight(year - 1, 12,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
mNextViewHeight = CalendarUtil.getMonthViewHeight(year, 2,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
} else {
mPreViewHeight = CalendarUtil.getMonthViewHeight(year, month - 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
if (month == 12) {
mNextViewHeight = CalendarUtil.getMonthViewHeight(year + 1, 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
} else {
mNextViewHeight = CalendarUtil.getMonthViewHeight(year, month + 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
}
}
}
/**
* 刷新
*/
void notifyDataSetChanged() {
mMonthCount = 12 * (mDelegate.getMaxYear() - mDelegate.getMinYear())
- mDelegate.getMinYearMonth() + 1 +
mDelegate.getMaxYearMonth();
notifyAdapterDataSetChanged();
}
/**
* 更新月视图Class
*/
void updateMonthViewClass() {
isUpdateMonthView = true;
notifyAdapterDataSetChanged();
isUpdateMonthView = false;
}
/**
* 更新日期范围
*/
final void updateRange() {
isUpdateMonthView = true;
notifyDataSetChanged();
isUpdateMonthView = false;
if (getVisibility() != VISIBLE) {
return;
}
isUsingScrollToCalendar = false;
Calendar calendar = mDelegate.mSelectedCalendar;
int y = calendar.getYear() - mDelegate.getMinYear();
int position = 12 * y + calendar.getMonth() - mDelegate.getMinYearMonth();
setCurrentItem(position, false);
BaseMonthView view = findViewWithTag(position);
if (view != null) {
view.setSelectedCalendar(mDelegate.mIndexCalendar);
view.invalidate();
if (mParentLayout != null) {
mParentLayout.updateSelectPosition(view.getSelectedIndex(mDelegate.mIndexCalendar));
}
}
if (mParentLayout != null) {
int week = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(week);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, false);
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, false);
}
updateSelected();
}
/**
* 滚动到指定日期
*
* @param year 年
* @param month 月
* @param day 日
* @param invokeListener 调用日期事件
*/
void scrollToCalendar(int year, int month, int day, boolean smoothScroll, boolean invokeListener) {
isUsingScrollToCalendar = true;
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setCurrentDay(calendar.equals(mDelegate.getCurrentDay()));
LunarCalendar.setupLunarCalendar(calendar);
mDelegate.mIndexCalendar = calendar;
mDelegate.mSelectedCalendar = calendar;
mDelegate.updateSelectCalendarScheme();
int y = calendar.getYear() - mDelegate.getMinYear();
int position = 12 * y + calendar.getMonth() - mDelegate.getMinYearMonth();
int curItem = getCurrentItem();
if (curItem == position) {
isUsingScrollToCalendar = false;
}
setCurrentItem(position, smoothScroll);
BaseMonthView view = findViewWithTag(position);
if (view != null) {
view.setSelectedCalendar(mDelegate.mIndexCalendar);
view.invalidate();
if (mParentLayout != null) {
mParentLayout.updateSelectPosition(view.getSelectedIndex(mDelegate.mIndexCalendar));
}
}
if (mParentLayout != null) {
int week = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(week);
}
if (mDelegate.mCalendarSelectListener != null && invokeListener) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, false);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, false);
}
updateSelected();
}
/**
* 滚动到当前日期
*/
void scrollToCurrent(boolean smoothScroll) {
isUsingScrollToCalendar = true;
int position = 12 * (mDelegate.getCurrentDay().getYear() - mDelegate.getMinYear()) +
mDelegate.getCurrentDay().getMonth() - mDelegate.getMinYearMonth();
int curItem = getCurrentItem();
if (curItem == position) {
isUsingScrollToCalendar = false;
}
setCurrentItem(position, smoothScroll);
BaseMonthView view = findViewWithTag(position);
if (view != null) {
view.setSelectedCalendar(mDelegate.getCurrentDay());
view.invalidate();
if (mParentLayout != null) {
mParentLayout.updateSelectPosition(view.getSelectedIndex(mDelegate.getCurrentDay()));
}
}
if (mDelegate.mCalendarSelectListener != null && getVisibility() == VISIBLE) {
mDelegate.mCalendarSelectListener.onCalendarSelect(mDelegate.mSelectedCalendar, false);
}
}
/**
* 获取当前月份数据
*
* @return 获取当前月份数据
*/
List<Calendar> getCurrentMonthCalendars() {
BaseMonthView view = findViewWithTag(getCurrentItem());
if (view == null) {
return null;
}
return view.mItems;
}
/**
* 更新为默认选择模式
*/
void updateDefaultSelect() {
BaseMonthView view = findViewWithTag(getCurrentItem());
if (view != null) {
int index = view.getSelectedIndex(mDelegate.mSelectedCalendar);
view.mCurrentItem = index;
if (index >= 0 && mParentLayout != null) {
mParentLayout.updateSelectPosition(index);
}
view.invalidate();
}
}
/**
* 更新选择效果
*/
void updateSelected() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.setSelectedCalendar(mDelegate.mSelectedCalendar);
view.invalidate();
}
}
/**
* 更新字体颜色大小
*/
final void updateStyle() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.updateStyle();
view.invalidate();
}
}
/**
* 更新标记日期
*/
void updateScheme() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.update();
}
}
/**
* 更新当前日期,夜间过度的时候调用这个函数,一般不需要调用
*/
void updateCurrentDate() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.updateCurrentDate();
}
}
/**
* 更新显示模式
*/
void updateShowMode() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.updateShowMode();
view.requestLayout();
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ALL_MONTH) {
mCurrentViewHeight = 6 * mDelegate.getCalendarItemHeight();
mNextViewHeight = mCurrentViewHeight;
mPreViewHeight = mCurrentViewHeight;
} else {
updateMonthViewHeight(mDelegate.mSelectedCalendar.getYear(), mDelegate.mSelectedCalendar.getMonth());
}
ViewGroup.LayoutParams params = getLayoutParams();
params.height = mCurrentViewHeight;
setLayoutParams(params);
if (mParentLayout != null) {
mParentLayout.updateContentViewTranslateY();
}
}
/**
* 更新周起始
*/
void updateWeekStart() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.updateWeekStart();
view.requestLayout();
}
updateMonthViewHeight(mDelegate.mSelectedCalendar.getYear(), mDelegate.mSelectedCalendar.getMonth());
ViewGroup.LayoutParams params = getLayoutParams();
params.height = mCurrentViewHeight;
setLayoutParams(params);
if (mParentLayout != null) {
int i = CalendarUtil.getWeekFromDayInMonth(mDelegate.mSelectedCalendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
updateSelected();
}
/**
* 更新高度
*/
final void updateItemHeight() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.updateItemHeight();
view.requestLayout();
}
int year = mDelegate.mIndexCalendar.getYear();
int month = mDelegate.mIndexCalendar.getMonth();
mCurrentViewHeight = CalendarUtil.getMonthViewHeight(year, month,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
if (month == 1) {
mPreViewHeight = CalendarUtil.getMonthViewHeight(year - 1, 12,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
mNextViewHeight = CalendarUtil.getMonthViewHeight(year, 2,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
} else {
mPreViewHeight = CalendarUtil.getMonthViewHeight(year, month - 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
if (month == 12) {
mNextViewHeight = CalendarUtil.getMonthViewHeight(year + 1, 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
} else {
mNextViewHeight = CalendarUtil.getMonthViewHeight(year, month + 1,
mDelegate.getCalendarItemHeight(), mDelegate.getWeekStart(),
mDelegate.getMonthViewShowMode());
}
}
ViewGroup.LayoutParams params = getLayoutParams();
params.height = mCurrentViewHeight;
setLayoutParams(params);
}
/**
* 清除选择范围
*/
final void clearSelectRange() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.invalidate();
}
}
/**
* 清除单选选择
*/
final void clearSingleSelect() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.mCurrentItem = -1;
view.invalidate();
}
}
/**
* 清除单选选择
*/
final void clearMultiSelect() {
for (int i = 0; i < getChildCount(); i++) {
BaseMonthView view = (BaseMonthView) getChildAt(i);
view.mCurrentItem = -1;
view.invalidate();
}
}
private void notifyAdapterDataSetChanged() {
if (getAdapter() == null) {
return;
}
getAdapter().notifyDataSetChanged();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
return mDelegate.isMonthViewScrollable() && super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDelegate.isMonthViewScrollable() && super.onInterceptTouchEvent(ev);
}
@Override
public void setCurrentItem(int item) {
setCurrentItem(item, true);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
if (Math.abs(getCurrentItem() - item) > 1) {
super.setCurrentItem(item, false);
} else {
super.setCurrentItem(item, smoothScroll);
}
}
/**
* 日历卡月份Adapter
*/
private final class MonthViewPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return mMonthCount;
}
@Override
public int getItemPosition(@NonNull Object object) {
return isUpdateMonthView ? POSITION_NONE : super.getItemPosition(object);
}
@Override
public boolean isViewFromObject(View view, @NonNull Object object) {
return view.equals(object);
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
int year = (position + mDelegate.getMinYearMonth() - 1) / 12 + mDelegate.getMinYear();
int month = (position + mDelegate.getMinYearMonth() - 1) % 12 + 1;
BaseMonthView view;
try {
Constructor constructor = mDelegate.getMonthViewClass().getConstructor(Context.class);
view = (BaseMonthView) constructor.newInstance(getContext());
} catch (Exception e) {
e.printStackTrace();
return new DefaultMonthView(getContext());
}
view.mMonthViewPager = MonthViewPager.this;
view.mParentLayout = mParentLayout;
view.setup(mDelegate);
view.setTag(position);
view.initMonthWithDate(year, month);
view.setSelectedCalendar(mDelegate.mSelectedCalendar);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
BaseView view = (BaseView) object;
view.onDestroy();
container.removeView(view);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 多选月视图
*/
public abstract class MultiMonthView extends BaseMonthView {
public MultiMonthView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
if (mLineCount == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
int count = mLineCount * 7;
int d = 0;
for (int i = 0; i < mLineCount; i++) {
for (int j = 0; j < 7; j++) {
Calendar calendar = mItems.get(d);
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH) {
if (d > mItems.size() - mNextDiff) {
return;
}
if (!calendar.isCurrentMonth()) {
++d;
continue;
}
} else if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_FIT_MONTH) {
if (d >= count) {
return;
}
}
draw(canvas, calendar, d, i, j);
++d;
}
}
}
/**
* 开始绘制
*
* @param canvas canvas
* @param calendar 对应日历
* @param i i
* @param j j
*/
private void draw(Canvas canvas, Calendar calendar, int calendarIndex, int i, int j) {
int x = j * mItemWidth + mDelegate.getCalendarPaddingLeft();
int y = i * mItemHeight;
onLoopStart(x, y);
boolean isSelected = isCalendarSelected(calendar);
boolean hasScheme = calendar.hasScheme();
boolean isPreSelected = isSelectPreCalendar(calendar, calendarIndex);
boolean isNextSelected = isSelectNextCalendar(calendar, calendarIndex);
if (hasScheme) {
//标记的日子
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, y, true, isPreSelected, isNextSelected);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, y, true);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, y, false, isPreSelected, isNextSelected);
}
}
onDrawText(canvas, calendar, x, y, hasScheme, isSelected);
}
/**
* 日历是否被选中
*
* @param calendar calendar
* @return 日历是否被选中
*/
protected boolean isCalendarSelected(Calendar calendar) {
return !onCalendarIntercept(calendar) && mDelegate.mSelectedCalendars.containsKey(calendar.toString());
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH
&& !calendar.isCurrentMonth()) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onCalendarMultiSelectOutOfRange(calendar);
}
return;
}
String key = calendar.toString();
if (mDelegate.mSelectedCalendars.containsKey(key)) {
mDelegate.mSelectedCalendars.remove(key);
} else {
if (mDelegate.mSelectedCalendars.size() >= mDelegate.getMaxMultiSelectSize()) {
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onMultiSelectOutOfSize(calendar,
mDelegate.getMaxMultiSelectSize());
}
return;
}
mDelegate.mSelectedCalendars.put(key, calendar);
}
mCurrentItem = mItems.indexOf(calendar);
if (!calendar.isCurrentMonth() && mMonthViewPager != null) {
int cur = mMonthViewPager.getCurrentItem();
int position = mCurrentItem < 7 ? cur - 1 : cur + 1;
mMonthViewPager.setCurrentItem(position);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, true);
}
if (mParentLayout != null) {
if (calendar.isCurrentMonth()) {
mParentLayout.updateSelectPosition(mItems.indexOf(calendar));
} else {
mParentLayout.updateSelectWeek(CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart()));
}
}
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onCalendarMultiSelect(
calendar,
mDelegate.mSelectedCalendars.size(),
mDelegate.getMaxMultiSelectSize());
}
}
@Override
public boolean onLongClick(View v) {
return false;
}
/**
* 上一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 上一个日期是否选中
*/
protected final boolean isSelectPreCalendar(Calendar calendar, int calendarIndex) {
Calendar preCalendar;
if (calendarIndex == 0) {
preCalendar = CalendarUtil.getPreCalendar(calendar);
mDelegate.updateCalendarScheme(preCalendar);
} else {
preCalendar = mItems.get(calendarIndex - 1);
}
return isCalendarSelected(preCalendar);
}
/**
* 下一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 下一个日期是否选中
*/
protected final boolean isSelectNextCalendar(Calendar calendar, int calendarIndex) {
Calendar nextCalendar;
if (calendarIndex == mItems.size() - 1) {
nextCalendar = CalendarUtil.getNextCalendar(calendar);
mDelegate.updateCalendarScheme(nextCalendar);
} else {
nextCalendar = mItems.get(calendarIndex + 1);
}
return isCalendarSelected(nextCalendar);
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @param isSelectedPre 上一个日期是否选中
* @param isSelectedNext 下一个日期是否选中
* @return 是否继续绘制onDrawScheme,true or false
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext);
/**
* 绘制标记的日期,这里可以是背景色,标记色什么的
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param isSelected 是否选中
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y, boolean isSelected);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 多选周视图
*/
public abstract class MultiWeekView extends BaseWeekView {
public MultiWeekView(Context context) {
super(context);
}
/**
* 绘制日历文本
*
* @param canvas canvas
*/
@Override
protected void onDraw(Canvas canvas) {
if (mItems.size() == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
for (int i = 0; i < 7; i++) {
int x = i * mItemWidth + mDelegate.getCalendarPaddingLeft();
onLoopStart(x);
Calendar calendar = mItems.get(i);
boolean isSelected = isCalendarSelected(calendar);
boolean isPreSelected = isSelectPreCalendar(calendar, i);
boolean isNextSelected = isSelectNextCalendar(calendar, i);
boolean hasScheme = calendar.hasScheme();
if (hasScheme) {
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, true, isPreSelected, isNextSelected);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, isSelected);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, false, isPreSelected, isNextSelected);
}
}
onDrawText(canvas, calendar, x, hasScheme, isSelected);
}
}
/**
* 日历是否被选中
*
* @param calendar calendar
* @return 日历是否被选中
*/
protected boolean isCalendarSelected(Calendar calendar) {
return !onCalendarIntercept(calendar) && mDelegate.mSelectedCalendars.containsKey(calendar.toString());
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onCalendarMultiSelectOutOfRange(calendar);
}
return;
}
String key = calendar.toString();
if (mDelegate.mSelectedCalendars.containsKey(key)) {
mDelegate.mSelectedCalendars.remove(key);
} else {
if (mDelegate.mSelectedCalendars.size() >= mDelegate.getMaxMultiSelectSize()) {
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onMultiSelectOutOfSize(calendar,
mDelegate.getMaxMultiSelectSize());
}
return;
}
mDelegate.mSelectedCalendars.put(key, calendar);
}
mCurrentItem = mItems.indexOf(calendar);
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, true);
}
if (mParentLayout != null) {
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
if (mDelegate.mCalendarMultiSelectListener != null) {
mDelegate.mCalendarMultiSelectListener.onCalendarMultiSelect(
calendar,
mDelegate.mSelectedCalendars.size(),
mDelegate.getMaxMultiSelectSize());
}
invalidate();
}
@Override
public boolean onLongClick(View v) {
return false;
}
/**
* 上一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 上一个日期是否选中
*/
protected final boolean isSelectPreCalendar(Calendar calendar, int calendarIndex) {
Calendar preCalendar;
if (calendarIndex == 0) {
preCalendar = CalendarUtil.getPreCalendar(calendar);
mDelegate.updateCalendarScheme(preCalendar);
} else {
preCalendar = mItems.get(calendarIndex - 1);
}
return isCalendarSelected(preCalendar);
}
/**
* 下一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 下一个日期是否选中
*/
protected final boolean isSelectNextCalendar(Calendar calendar, int calendarIndex) {
Calendar nextCalendar;
if (calendarIndex == mItems.size() - 1) {
nextCalendar = CalendarUtil.getNextCalendar(calendar);
mDelegate.updateCalendarScheme(nextCalendar);
} else {
nextCalendar = mItems.get(calendarIndex + 1);
}
return isCalendarSelected(nextCalendar);
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @param isSelectedPre 上一个日期是否选中
* @param isSelectedNext 下一个日期是否选中
* @return 是否绘制 onDrawScheme
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext);
/**
* 绘制标记的日期
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param isSelected 是否选中
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, boolean isSelected);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 范围选择月视图
*/
public abstract class RangeMonthView extends BaseMonthView {
public RangeMonthView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
if (mLineCount == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
int count = mLineCount * 7;
int d = 0;
for (int i = 0; i < mLineCount; i++) {
for (int j = 0; j < 7; j++) {
Calendar calendar = mItems.get(d);
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH) {
if (d > mItems.size() - mNextDiff) {
return;
}
if (!calendar.isCurrentMonth()) {
++d;
continue;
}
} else if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_FIT_MONTH) {
if (d >= count) {
return;
}
}
draw(canvas, calendar, d, i, j);
++d;
}
}
}
/**
* 开始绘制
*
* @param canvas canvas
* @param calendar 对应日历
* @param i i
* @param j j
*/
private void draw(Canvas canvas, Calendar calendar, int calendarIndex, int i, int j) {
int x = j * mItemWidth + mDelegate.getCalendarPaddingLeft();
int y = i * mItemHeight;
onLoopStart(x, y);
boolean isSelected = isCalendarSelected(calendar);
boolean hasScheme = calendar.hasScheme();
boolean isPreSelected = isSelectPreCalendar(calendar, calendarIndex);
boolean isNextSelected = isSelectNextCalendar(calendar, calendarIndex);
if (hasScheme) {
//标记的日子
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, y, true, isPreSelected, isNextSelected);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, y, true);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, y, false, isPreSelected, isNextSelected);
}
}
onDrawText(canvas, calendar, x, y, hasScheme, isSelected);
}
/**
* 日历是否被选中
*
* @param calendar calendar
* @return 日历是否被选中
*/
protected boolean isCalendarSelected(Calendar calendar) {
if (mDelegate.mSelectedStartRangeCalendar == null) {
return false;
}
if (onCalendarIntercept(calendar)) {
return false;
}
if (mDelegate.mSelectedEndRangeCalendar == null) {
return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) == 0;
}
return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) >= 0 &&
calendar.compareTo(mDelegate.mSelectedEndRangeCalendar) <= 0;
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (mDelegate.getMonthViewShowMode() == CalendarViewDelegate.MODE_ONLY_CURRENT_MONTH
&& !calendar.isCurrentMonth()) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarSelectOutOfRange(calendar);
}
return;
}
//优先判断各种直接return的情况,减少代码深度
if (mDelegate.mSelectedStartRangeCalendar != null && mDelegate.mSelectedEndRangeCalendar == null) {
int minDiffer = CalendarUtil.differ(calendar, mDelegate.mSelectedStartRangeCalendar);
if (minDiffer >= 0 && mDelegate.getMinSelectRange() != -1 && mDelegate.getMinSelectRange() > minDiffer + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(calendar, true);
}
return;
} else if (mDelegate.getMaxSelectRange() != -1 && mDelegate.getMaxSelectRange() <
CalendarUtil.differ(calendar, mDelegate.mSelectedStartRangeCalendar) + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(calendar, false);
}
return;
}
}
if (mDelegate.mSelectedStartRangeCalendar == null || mDelegate.mSelectedEndRangeCalendar != null) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else {
int compare = calendar.compareTo(mDelegate.mSelectedStartRangeCalendar);
if (mDelegate.getMinSelectRange() == -1 && compare <= 0) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else if (compare < 0) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else if (compare == 0 &&
mDelegate.getMinSelectRange() == 1) {
mDelegate.mSelectedEndRangeCalendar = calendar;
} else {
mDelegate.mSelectedEndRangeCalendar = calendar;
}
}
mCurrentItem = mItems.indexOf(calendar);
if (!calendar.isCurrentMonth() && mMonthViewPager != null) {
int cur = mMonthViewPager.getCurrentItem();
int position = mCurrentItem < 7 ? cur - 1 : cur + 1;
mMonthViewPager.setCurrentItem(position);
}
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onMonthDateSelected(calendar, true);
}
if (mParentLayout != null) {
if (calendar.isCurrentMonth()) {
mParentLayout.updateSelectPosition(mItems.indexOf(calendar));
} else {
mParentLayout.updateSelectWeek(CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart()));
}
}
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarRangeSelect(calendar,
mDelegate.mSelectedEndRangeCalendar != null);
}
}
@Override
public boolean onLongClick(View v) {
return false;
}
/**
* 上一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 上一个日期是否选中
*/
protected final boolean isSelectPreCalendar(Calendar calendar, int calendarIndex) {
Calendar preCalendar;
if (calendarIndex == 0) {
preCalendar = CalendarUtil.getPreCalendar(calendar);
mDelegate.updateCalendarScheme(preCalendar);
} else {
preCalendar = mItems.get(calendarIndex - 1);
}
return mDelegate.mSelectedStartRangeCalendar != null &&
isCalendarSelected(preCalendar);
}
/**
* 下一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 下一个日期是否选中
*/
protected final boolean isSelectNextCalendar(Calendar calendar, int calendarIndex) {
Calendar nextCalendar;
if (calendarIndex == mItems.size() - 1) {
nextCalendar = CalendarUtil.getNextCalendar(calendar);
mDelegate.updateCalendarScheme(nextCalendar);
} else {
nextCalendar = mItems.get(calendarIndex + 1);
}
return mDelegate.mSelectedStartRangeCalendar != null &&
isCalendarSelected(nextCalendar);
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @param isSelectedPre 上一个日期是否选中
* @param isSelectedNext 下一个日期是否选中
* @return 是否继续绘制onDrawScheme,true or false
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext);
/**
* 绘制标记的日期,这里可以是背景色,标记色什么的
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param isSelected 是否选中
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y, boolean isSelected);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 范围选择周视图
*/
public abstract class RangeWeekView extends BaseWeekView {
public RangeWeekView(Context context) {
super(context);
}
/**
* 绘制日历文本
*
* @param canvas canvas
*/
@Override
protected void onDraw(Canvas canvas) {
if (mItems.size() == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
for (int i = 0; i < 7; i++) {
int x = i * mItemWidth + mDelegate.getCalendarPaddingLeft();
onLoopStart(x);
Calendar calendar = mItems.get(i);
boolean isSelected = isCalendarSelected(calendar);
boolean isPreSelected = isSelectPreCalendar(calendar, i);
boolean isNextSelected = isSelectNextCalendar(calendar, i);
boolean hasScheme = calendar.hasScheme();
if (hasScheme) {
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, true, isPreSelected, isNextSelected);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, isSelected);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, false, isPreSelected, isNextSelected);
}
}
onDrawText(canvas, calendar, x, hasScheme, isSelected);
}
}
/**
* 日历是否被选中
*
* @param calendar calendar
* @return 日历是否被选中
*/
protected boolean isCalendarSelected(Calendar calendar) {
if (mDelegate.mSelectedStartRangeCalendar == null) {
return false;
}
if (onCalendarIntercept(calendar)) {
return false;
}
if (mDelegate.mSelectedEndRangeCalendar == null) {
return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) == 0;
}
return calendar.compareTo(mDelegate.mSelectedStartRangeCalendar) >= 0 &&
calendar.compareTo(mDelegate.mSelectedEndRangeCalendar) <= 0;
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarSelectOutOfRange(calendar);
}
return;
}
//优先判断各种直接return的情况,减少代码深度
if (mDelegate.mSelectedStartRangeCalendar != null && mDelegate.mSelectedEndRangeCalendar == null) {
int minDiffer = CalendarUtil.differ(calendar, mDelegate.mSelectedStartRangeCalendar);
if (minDiffer >= 0 && mDelegate.getMinSelectRange() != -1 && mDelegate.getMinSelectRange() > minDiffer + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(calendar, true);
}
return;
} else if (mDelegate.getMaxSelectRange() != -1 && mDelegate.getMaxSelectRange() <
CalendarUtil.differ(calendar, mDelegate.mSelectedStartRangeCalendar) + 1) {
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onSelectOutOfRange(calendar, false);
}
return;
}
}
if (mDelegate.mSelectedStartRangeCalendar == null || mDelegate.mSelectedEndRangeCalendar != null) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else {
int compare = calendar.compareTo(mDelegate.mSelectedStartRangeCalendar);
if (mDelegate.getMinSelectRange() == -1 && compare <= 0) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else if (compare < 0) {
mDelegate.mSelectedStartRangeCalendar = calendar;
mDelegate.mSelectedEndRangeCalendar = null;
} else if (compare == 0 &&
mDelegate.getMinSelectRange() == 1) {
mDelegate.mSelectedEndRangeCalendar = calendar;
} else {
mDelegate.mSelectedEndRangeCalendar = calendar;
}
}
mCurrentItem = mItems.indexOf(calendar);
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, true);
}
if (mParentLayout != null) {
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
if (mDelegate.mCalendarRangeSelectListener != null) {
mDelegate.mCalendarRangeSelectListener.onCalendarRangeSelect(calendar,
mDelegate.mSelectedEndRangeCalendar != null);
}
invalidate();
}
@Override
public boolean onLongClick(View v) {
return false;
}
/**
* 上一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 上一个日期是否选中
*/
protected final boolean isSelectPreCalendar(Calendar calendar, int calendarIndex) {
Calendar preCalendar;
if (calendarIndex == 0) {
preCalendar = CalendarUtil.getPreCalendar(calendar);
mDelegate.updateCalendarScheme(preCalendar);
} else {
preCalendar = mItems.get(calendarIndex - 1);
}
return mDelegate.mSelectedStartRangeCalendar != null &&
isCalendarSelected(preCalendar);
}
/**
* 下一个日期是否选中
*
* @param calendar 当前日期
* @param calendarIndex 当前位置
* @return 下一个日期是否选中
*/
protected final boolean isSelectNextCalendar(Calendar calendar, int calendarIndex) {
Calendar nextCalendar;
if (calendarIndex == mItems.size() - 1) {
nextCalendar = CalendarUtil.getNextCalendar(calendar);
mDelegate.updateCalendarScheme(nextCalendar);
} else {
nextCalendar = mItems.get(calendarIndex + 1);
}
return mDelegate.mSelectedStartRangeCalendar != null &&
isCalendarSelected(nextCalendar);
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @param isSelectedPre 上一个日期是否选中
* @param isSelectedNext 下一个日期是否选中
* @return 是否绘制 onDrawScheme
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext);
/**
* 绘制标记的日期
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param isSelected 是否选中
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, boolean isSelected);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected);
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* 高仿魅族日历布局
*/
public class SimpleMonthView extends MonthView {
private int mRadius;
public SimpleMonthView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onLoopStart(int x, int y) {
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* 简单周视图
*/
public class SimpleWeekView extends WeekView {
private int mRadius;
public SimpleWeekView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine;
int cx = x + mItemWidth / 2;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mSchemeTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import com.sobot.widget.R;
/**
* http://www.cnblogs.com/moodlxs/archive/2010/12/18/2345392.html
* 24节气计算公式,参考该博客实现
*/
@SuppressWarnings("all")
public final class SolarTermUtil {
static void init(Context context) {
SOLAR_TERMS = context.getResources().getStringArray(R.array.solar_term);
}
/**
* 24节气
*/
private static String SOLAR_TERMS[] = null;
/**
* 每弧度的角秒数
*/
private static final double SECOND_PER_RAD = 180 * 3600 / Math.PI;
/**
* 每弧度的角度数
*/
private static final double ANGLE_PER_RAD = 180 / Math.PI;
/**
* 日历计算
* 2000年前儒略日数(2000-1-1)
*/
private static final double J2000 = 2451545;
/**
* 黄赤交角系数表
*/
private static final double H_C_ANGLE_TABLE[] = {0, 50287.92262, 111.24406,
0.07699, -0.23479, -0.00178, 0.00018, 0.00001};
/**
* 世界时与原子时之差计算表
*/
private static final double[] DTS = {
-4000, 108371.7, -13036.80, 392.000, 0.0000, -500, 17201.0,
-627.82, 16.170, -0.3413, -150, 12200.6, -346.41, 5.403, -0.1593,
150, 9113.8, -328.13, -1.647, 0.0377, 500, 5707.5, -391.41, 0.915,
0.3145, 900, 2203.4, -283.45, 13.034, -0.1778, 1300, 490.1, -57.35,
2.085, -0.0072, 1600, 120.0, -9.81, -1.532, 0.1403, 1700, 10.2,
-0.91, 0.510, -0.0370, 1800, 13.4, -0.72, 0.202, -0.0193, 1830,
7.8, -1.81, 0.416, -0.0247, 1860, 8.3, -0.13, -0.406, 0.0292, 1880,
-5.4, 0.32, -0.183, 0.0173, 1900, -2.3, 2.06, 0.169, -0.0135, 1920,
21.2, 1.69, -0.304, 0.0167, 1940, 24.2, 1.22, -0.064, 0.0031, 1960,
33.2, 0.51, 0.231, -0.0109, 1980, 51.0, 1.29, -0.026, 0.0032, 2000,
64.7, -1.66, 5.224, -0.2905, 2150, 279.4, 732.95, 429.579, 0.0158,
6000};
/**
* 离心率
*/
private static final double GXC_E[] = {0.016708634, -0.000042037,
-0.0000001267};
/**
* 近点
*/
private static final double GXC_P[] = {102.93735 / ANGLE_PER_RAD, 1.71946 / ANGLE_PER_RAD,
0.00046 / ANGLE_PER_RAD};
/**
* 太平黄经
*/
private static final double GXC_L[] = {280.4664567 / ANGLE_PER_RAD,
36000.76982779 / ANGLE_PER_RAD, 0.0003032028 / ANGLE_PER_RAD, 1 / 49931000 / ANGLE_PER_RAD,
-1 / 153000000 / ANGLE_PER_RAD};
/**
* 光行差常数
*/
private static final double GXC_K = 20.49552 / SECOND_PER_RAD;
/**
* 向下取整
*
* @param v v
* @return 取整数部分
*/
private static double doubleFloor(double v) {
v = Math.floor(v);
if (v < 0)
return v + 1;
return v;
}
/**
* 对超过0-2PI的角度转为0-2PI
*
* @param v v
* @return 对超过0-2PI的角度转为0-2PI
*/
private static double rad2mrad(double v) {
v = v % (2 * Math.PI);
if (v < 0)
return v + 2 * Math.PI;
return v;
}
/**
* 计算世界时与原子时之差,传入年
*
* @param year 年
* @return 计算世界时与原子时之差
*/
private static double worldTimeDiff(double year) {
int i;
for (i = 0; i < 100; i += 5)
if (year < DTS[i + 5] || i == 95)
break;
double t1 = (year - DTS[i]) / (DTS[i + 5] - DTS[i]) * 10;
double t2 = t1 * t1;
double t3 = t2 * t1;
return DTS[i + 1] + DTS[i + 2] * t1 + DTS[i + 3] * t2 + DTS[i + 4] * t3;
}
/**
* 传入儒略日(J2000起算),计算UTC与原子时的差(单位:日)
*
* @param julian 儒略日
* @return 计算UTC与原子时的差
*/
private static double atomTimeDiff(double julian) {
return worldTimeDiff(julian / 365.2425 + 2000) / 86400.0;
}
/**
* 公历转儒略日,UTC=1表示原日期是UTC
*
* @param UTC UTC
* @return 公历转儒略日, UTC=1表示原日期是UTC
*/
private static double toJulian(Time time, boolean UTC) {
double y = time.year; // 取出年月
double m = time.month;
double n = 0;
if (m <= 2) {
m += 12;
y--;
}
if (time.year * 372 + time.month * 31 + time.day >= 588829) {
// 判断是否为格里高利历日1582*372+10*31+15
n = doubleFloor(y / 100);
n = 2 - n + doubleFloor(n / 4);// 加百年闰
}
n += doubleFloor(365.2500001 * (y + 4716)); // 加上年引起的偏移日数
n += doubleFloor(30.6 * (m + 1)) + time.day; // 加上月引起的偏移日数及日偏移数
n += ((time.second / 60 + time.minute) / 60 + time.hour) / 24 - 1524.5;
if (UTC)
return n + atomTimeDiff(n - J2000);
return n;
}
/**
* 儒略日数转公历,UTC=1表示目标公历是UTC
*
* @param jd jd
* @param UTC UTC
*/
@SuppressWarnings("all")
private static Time setFromJulian(double jd, boolean UTC) {
Time time = new Time();
if (UTC)
jd -= atomTimeDiff(jd - J2000);
jd += 0.5;
// 取得日数的整数部份A及小数部分F
double A = doubleFloor(jd);
double F = jd - A;
double D;
if (A > 2299161) {
D = doubleFloor((A - 1867216.25) / 36524.25);
A += 1 + D - doubleFloor(D / 4);
}
A += 1524; // 向前移4年零2个月
time.year = doubleFloor((A - 122.1) / 365.25);// 年
D = A - doubleFloor(365.25 * time.year); // 去除整年日数后余下日数
time.month = doubleFloor(D / 30.6001); // 月数
time.day = D - doubleFloor(time.month * 30.6001);// 去除整月日数后余下日数
time.year -= 4716;
time.month--;
if (time.month > 12)
time.month -= 12;
if (time.month <= 2)
time.year++;
// 日的小数转为时分秒
F *= 24;
time.hour = doubleFloor(F);
F -= time.hour;
F *= 60;
time.minute = doubleFloor(F);
F -= time.minute;
F *= 60;
time.second = F;
return time;
}
/**
* 补岁差
*
* @param jd jd
* @param zb zb
*/
private static void precession(double jd, double[] zb) {
int i;
double t = 1, v = 0, t1 = jd / 365250;
for (i = 1; i < 8; i++) {
t *= t1;
v += H_C_ANGLE_TABLE[i] * t;
}
zb[0] = rad2mrad(zb[0] + (v + 2.9965 * t1) / SECOND_PER_RAD);
}
/**
* 恒星周年光行差计算(黄道坐标中)
*
* @param t t
* @param zb zb
*/
private static void addGxc(double t, double[] zb) {
double t1 = t / 36525;
double t2 = t1 * t1;
double t3 = t2 * t1;
double t4 = t3 * t1;
double L = GXC_L[0] + GXC_L[1] * t1 + GXC_L[2] * t2 + GXC_L[3] * t3
+ GXC_L[4] * t4;
double p = GXC_P[0] + GXC_P[1] * t1 + GXC_P[2] * t2;
double e = GXC_E[0] + GXC_E[1] * t1 + GXC_E[2] * t2;
double dL = L - zb[0], dP = p - zb[0];
zb[0] -= GXC_K * (Math.cos(dL) - e * Math.cos(dP)) / Math.cos(zb[1]);
zb[1] -= GXC_K * Math.sin(zb[1]) * (Math.sin(dL) - e * Math.sin(dP));
zb[0] = rad2mrad(zb[0]);
}
/**
* 章动计算
*/
private static final double nutB[] = {// 章动表
2.1824391966, -33.757045954, 0.0000362262, 3.7340E-08, -2.8793E-10,
-171996, -1742, 92025, 89, 3.5069406862, 1256.663930738,
0.0000105845, 6.9813E-10, -2.2815E-10, -13187, -16, 5736, -31,
1.3375032491, 16799.418221925, -0.0000511866, 6.4626E-08,
-5.3543E-10, -2274, -2, 977, -5, 4.3648783932, -67.514091907,
0.0000724525, 7.4681E-08, -5.7586E-10, 2062, 2, -895, 5,
0.0431251803, -628.301955171, 0.0000026820, 6.5935E-10, 5.5705E-11,
-1426, 34, 54, -1, 2.3555557435, 8328.691425719, 0.0001545547,
2.5033E-07, -1.1863E-09, 712, 1, -7, 0, 3.4638155059,
1884.965885909, 0.0000079025, 3.8785E-11, -2.8386E-10, -517, 12,
224, -6, 5.4382493597, 16833.175267879, -0.0000874129, 2.7285E-08,
-2.4750E-10, -386, -4, 200, 0, 3.6930589926, 25128.109647645,
0.0001033681, 3.1496E-07, -1.7218E-09, -301, 0, 129, -1,
3.5500658664, 628.361975567, 0.0000132664, 1.3575E-09, -1.7245E-10,
217, -5, -95, 3};
/**
* 计算黄经章动及交角章动
*
* @param t t
* @return 计算黄经章动及交角章动
*/
private static Nutation nutation(double t) {
Nutation d = new Nutation();
d.Lon = 0;
d.Obl = 0;
t /= 36525;
double c, t1 = t, t2 = t1 * t1, t3 = t2 * t1, t4 = t3 * t1;// t5=t4*t1;
for (int i = 0; i < nutB.length; i += 9) {
c = nutB[i] + nutB[i + 1] * t1 + nutB[i + 2] * t2 + nutB[i + 3]
* t3 + nutB[i + 4] * t4;
d.Lon += (nutB[i + 5] + nutB[i + 6] * t / 10) * Math.sin(c); // 黄经章动
d.Obl += (nutB[i + 7] + nutB[i + 8] * t / 10) * Math.cos(c); // 交角章动
}
d.Lon /= SECOND_PER_RAD * 10000; // 黄经章动
d.Obl /= SECOND_PER_RAD * 10000; // 交角章动
return d;
}
//
/***************************************
* 如果用记事本查看此代码,请在"格式"菜单中去除"自动换行"
* E10是关于地球的,格式如下:
* 它是一个数组,每3个数看作一条记录,每条记录的3个数记为A,B,C
* rec=A*cos(B+C*t); 式中t是J2000起算的儒略千年数
* 每条记录的计算结果(即rec)取和即得地球的日心黄经的周期量L0
* E11格式如下: rec = A*cos*(B+C*t) *t, 取和后得泊松量L1
* E12格式如下: rec = A*cos*(B+C*t) *t*t, 取和后得泊松量L2
* E13格式如下: rec = A*cos*(B+C*t) *t*t*t, 取和后得泊松量L3
* 最后地球的地心黄经:L = L0+L1+L2+L3+...
* E20,E21,E22,E23...用于计算黄纬
* M10,M11等是关于月球的,参数的用法请阅读Mnn()函数
*****************************************/
//地球运动VSOP87参数
private static final double E10[] = { //黄经周期项
1.75347045673, 0.00000000000, 0.0000000000, 0.03341656456, 4.66925680417, 6283.0758499914, 0.00034894275, 4.62610241759, 12566.1516999828, 0.00003417571, 2.82886579606, 3.5231183490,
0.00003497056, 2.74411800971, 5753.3848848968, 0.00003135896, 3.62767041758, 77713.7714681205, 0.00002676218, 4.41808351397, 7860.4193924392, 0.00002342687, 6.13516237631, 3930.2096962196,
0.00001273166, 2.03709655772, 529.6909650946, 0.00001324292, 0.74246356352, 11506.7697697936, 0.00000901855, 2.04505443513, 26.2983197998, 0.00001199167, 1.10962944315, 1577.3435424478,
0.00000857223, 3.50849156957, 398.1490034082, 0.00000779786, 1.17882652114, 5223.6939198022, 0.00000990250, 5.23268129594, 5884.9268465832, 0.00000753141, 2.53339053818, 5507.5532386674,
0.00000505264, 4.58292563052, 18849.2275499742, 0.00000492379, 4.20506639861, 775.5226113240, 0.00000356655, 2.91954116867, 0.0673103028, 0.00000284125, 1.89869034186, 796.2980068164,
0.00000242810, 0.34481140906, 5486.7778431750, 0.00000317087, 5.84901952218, 11790.6290886588, 0.00000271039, 0.31488607649, 10977.0788046990, 0.00000206160, 4.80646606059, 2544.3144198834,
0.00000205385, 1.86947813692, 5573.1428014331, 0.00000202261, 2.45767795458, 6069.7767545534, 0.00000126184, 1.08302630210, 20.7753954924, 0.00000155516, 0.83306073807, 213.2990954380,
0.00000115132, 0.64544911683, 0.9803210682, 0.00000102851, 0.63599846727, 4694.0029547076, 0.00000101724, 4.26679821365, 7.1135470008, 0.00000099206, 6.20992940258, 2146.1654164752,
0.00000132212, 3.41118275555, 2942.4634232916, 0.00000097607, 0.68101272270, 155.4203994342, 0.00000085128, 1.29870743025, 6275.9623029906, 0.00000074651, 1.75508916159, 5088.6288397668,
0.00000101895, 0.97569221824, 15720.8387848784, 0.00000084711, 3.67080093025, 71430.6956181291, 0.00000073547, 4.67926565481, 801.8209311238, 0.00000073874, 3.50319443167, 3154.6870848956,
0.00000078756, 3.03698313141, 12036.4607348882, 0.00000079637, 1.80791330700, 17260.1546546904, 0.00000085803, 5.98322631256, 161000.6857376741, 0.00000056963, 2.78430398043, 6286.5989683404,
0.00000061148, 1.81839811024, 7084.8967811152, 0.00000069627, 0.83297596966, 9437.7629348870, 0.00000056116, 4.38694880779, 14143.4952424306, 0.00000062449, 3.97763880587, 8827.3902698748,
0.00000051145, 0.28306864501, 5856.4776591154, 0.00000055577, 3.47006009062, 6279.5527316424, 0.00000041036, 5.36817351402, 8429.2412664666, 0.00000051605, 1.33282746983, 1748.0164130670,
0.00000051992, 0.18914945834, 12139.5535091068, 0.00000049000, 0.48735065033, 1194.4470102246, 0.00000039200, 6.16832995016, 10447.3878396044, 0.00000035566, 1.77597314691, 6812.7668150860,
0.00000036770, 6.04133859347, 10213.2855462110, 0.00000036596, 2.56955238628, 1059.3819301892, 0.00000033291, 0.59309499459, 17789.8456197850, 0.00000035954, 1.70876111898, 2352.8661537718};
private static final double E11[] = { //黄经泊松1项
6283.31966747491, 0.00000000000, 0.0000000000, 0.00206058863, 2.67823455584, 6283.0758499914, 0.00004303430, 2.63512650414, 12566.1516999828, 0.00000425264, 1.59046980729, 3.5231183490,
0.00000108977, 2.96618001993, 1577.3435424478, 0.00000093478, 2.59212835365, 18849.2275499742, 0.00000119261, 5.79557487799, 26.2983197998, 0.00000072122, 1.13846158196, 529.6909650946,
0.00000067768, 1.87472304791, 398.1490034082, 0.00000067327, 4.40918235168, 5507.5532386674, 0.00000059027, 2.88797038460, 5223.6939198022, 0.00000055976, 2.17471680261, 155.4203994342,
0.00000045407, 0.39803079805, 796.2980068164, 0.00000036369, 0.46624739835, 775.5226113240, 0.00000028958, 2.64707383882, 7.1135470008, 0.00000019097, 1.84628332577, 5486.7778431750,
0.00000020844, 5.34138275149, 0.9803210682, 0.00000018508, 4.96855124577, 213.2990954380, 0.00000016233, 0.03216483047, 2544.3144198834, 0.00000017293, 2.99116864949, 6275.9623029906};
private static final double E12[] = { //黄经泊松2项
0.00052918870, 0.00000000000, 0.0000000000, 0.00008719837, 1.07209665242, 6283.0758499914, 0.00000309125, 0.86728818832, 12566.1516999828, 0.00000027339, 0.05297871691, 3.5231183490,
0.00000016334, 5.18826691036, 26.2983197998, 0.00000015752, 3.68457889430, 155.4203994342, 0.00000009541, 0.75742297675, 18849.2275499742, 0.00000008937, 2.05705419118, 77713.7714681205,
0.00000006952, 0.82673305410, 775.5226113240, 0.00000005064, 4.66284525271, 1577.3435424478};
private static final double E13[] = {0.00000289226, 5.84384198723, 6283.0758499914, 0.00000034955, 0.00000000000, 0.0000000000, 0.00000016819, 5.48766912348, 12566.1516999828};
private static final double E14[] = {0.00000114084, 3.14159265359, 0.0000000000, 0.00000007717, 4.13446589358, 6283.0758499914, 0.00000000765, 3.83803776214, 12566.1516999828};
private static final double E15[] = {0.00000000878, 3.14159265359, 0.0000000000};
private static final double E20[] = { //黄纬周期项
0.00000279620, 3.19870156017, 84334.6615813083, 0.00000101643, 5.42248619256, 5507.5532386674, 0.00000080445, 3.88013204458, 5223.6939198022, 0.00000043806, 3.70444689758, 2352.8661537718,
0.00000031933, 4.00026369781, 1577.3435424478, 0.00000022724, 3.98473831560, 1047.7473117547, 0.00000016392, 3.56456119782, 5856.4776591154, 0.00000018141, 4.98367470263, 6283.0758499914,
0.00000014443, 3.70275614914, 9437.7629348870, 0.00000014304, 3.41117857525, 10213.2855462110};
private static final double E21[] = {0.00000009030, 3.89729061890, 5507.5532386674, 0.00000006177, 1.73038850355, 5223.6939198022};
private static final double E30[] = { //距离周期项
1.00013988799, 0.00000000000, 0.0000000000, 0.01670699626, 3.09846350771, 6283.0758499914, 0.00013956023, 3.05524609620, 12566.1516999828, 0.00003083720, 5.19846674381, 77713.7714681205,
0.00001628461, 1.17387749012, 5753.3848848968, 0.00001575568, 2.84685245825, 7860.4193924392, 0.00000924799, 5.45292234084, 11506.7697697936, 0.00000542444, 4.56409149777, 3930.2096962196};
private static final double E31[] = {0.00103018608, 1.10748969588, 6283.0758499914, 0.00001721238, 1.06442301418, 12566.1516999828, 0.00000702215, 3.14159265359, 0.0000000000};
private static final double E32[] = {0.00004359385, 5.78455133738, 6283.0758499914};
private static final double E33[] = {0.00000144595, 4.27319435148, 6283.0758499914};
//月球运动参数
private static final double M10[] = {
22639.5858800, 2.3555545723, 8328.6914247251, 1.5231275E-04, 2.5041111E-07, -1.1863391E-09, 4586.4383203, 8.0413790709, 7214.0628654588, -2.1850087E-04, -1.8646419E-07, 8.7760973E-10, 2369.9139357, 10.3969336431, 15542.7542901840, -6.6188121E-05, 6.3946925E-08, -3.0872935E-10, 769.0257187, 4.7111091445, 16657.3828494503, 3.0462550E-04, 5.0082223E-07, -2.3726782E-09,
-666.4175399, -0.0431256817, 628.3019552485, -2.6638815E-06, 6.1639211E-10, -5.4439728E-11, -411.5957339, 3.2558104895, 16866.9323152810, -1.2804259E-04, -9.8998954E-09, 4.0433461E-11, 211.6555524, 5.6858244986, -1114.6285592663, -3.7081362E-04, -4.3687530E-07, 2.0639488E-09, 205.4359530, 8.0845047526, 6585.7609102104, -2.1583699E-04, -1.8708058E-07, 9.3204945E-10,
191.9561973, 12.7524882154, 23871.4457149091, 8.6124629E-05, 3.1435804E-07, -1.4950684E-09, 164.7286185, 10.4400593249, 14914.4523349355, -6.3524240E-05, 6.3330532E-08, -2.5428962E-10, -147.3213842, -2.3986802540, -7700.3894694766, -1.5497663E-04, -2.4979472E-07, 1.1318993E-09, -124.9881185, 5.1984668216, 7771.3771450920, -3.3094061E-05, 3.1973462E-08, -1.5436468E-10,
-109.3803637, 2.3124288905, 8956.9933799736, 1.4964887E-04, 2.5102751E-07, -1.2407788E-09, 55.1770578, 7.1411231536, -1324.1780250970, 6.1854469E-05, 7.3846820E-08, -3.4916281E-10, -45.0996092, 5.6113650618, 25195.6237400061, 2.4270161E-05, 2.4051122E-07, -1.1459056E-09, 39.5333010, -0.9002559173, -8538.2408905558, 2.8035534E-04, 2.6031101E-07, -1.2267725E-09,
38.4298346, 18.4383127140, 22756.8171556428, -2.8468899E-04, -1.2251727E-07, 5.6888037E-10, 36.1238141, 7.0666637168, 24986.0742741754, 4.5693825E-04, 7.5123334E-07, -3.5590172E-09, 30.7725751, 16.0827581417, 14428.1257309177, -4.3700174E-04, -3.7292838E-07, 1.7552195E-09, -28.3971008, 7.9982533891, 7842.3648207073, -2.2116475E-04, -1.8584780E-07, 8.2317000E-10,
-24.3582283, 10.3538079614, 16171.0562454324, -6.8852003E-05, 6.4563317E-08, -3.6316908E-10, -18.5847068, 2.8429122493, -557.3142796331, -1.8540681E-04, -2.1843765E-07, 1.0319744E-09, 17.9544674, 5.1553411398, 8399.6791003405, -3.5757942E-05, 3.2589854E-08, -2.0880440E-10, 14.5302779, 12.7956138971, 23243.1437596606, 8.8788511E-05, 3.1374165E-07, -1.4406287E-09,
14.3796974, 15.1080427876, 32200.1371396342, 2.3843738E-04, 5.6476915E-07, -2.6814075E-09, 14.2514576, -24.0810366320, -2.3011998397, 1.5231275E-04, 2.5041111E-07, -1.1863391E-09, 13.8990596, 20.7938672862, 31085.5085803679, -1.3237624E-04, 1.2789385E-07, -6.1745870E-10, 13.1940636, 3.3302699264, -9443.3199839914, -5.2312637E-04, -6.8728642E-07, 3.2502879E-09,
-9.6790568, -4.7542348263, -16029.0808942018, -3.0728938E-04, -5.0020584E-07, 2.3182384E-09, -9.3658635, 11.2971895604, 24080.9951807398, -3.4654346E-04, -1.9636409E-07, 9.1804319E-10, 8.6055318, 5.7289501804, -1742.9305145148, -3.6814974E-04, -4.3749170E-07, 2.1183885E-09, -8.4530982, 7.5540213938, 16100.0685698171, 1.1921869E-04, 2.8238458E-07, -1.3407038E-09,
8.0501724, 10.4831850066, 14286.1503796870, -6.0860358E-05, 6.2714140E-08, -1.9984990E-10, -7.6301553, 4.6679834628, 17285.6848046987, 3.0196162E-04, 5.0143862E-07, -2.4271179E-09, -7.4474952, -0.0862513635, 1256.6039104970, -5.3277630E-06, 1.2327842E-09, -1.0887946E-10, 7.3712011, 8.1276304344, 5957.4589549619, -2.1317311E-04, -1.8769697E-07, 9.8648918E-10,
7.0629900, 0.9591375719, 33.7570471374, -3.0829302E-05, -3.6967043E-08, 1.7385419E-10, -6.3831491, 9.4966777258, 7004.5133996281, 2.1416722E-04, 3.2425793E-07, -1.5355019E-09, -5.7416071, 13.6527441326, 32409.6866054649, -1.9423071E-04, 5.4047029E-08, -2.6829589E-10, 4.3740095, 18.4814383957, 22128.5152003943, -2.8202511E-04, -1.2313366E-07, 6.2332010E-10,
-3.9976134, 7.9669196340, 33524.3151647312, 1.7658291E-04, 4.9092233E-07, -2.3322447E-09, -3.2096876, 13.2398458924, 14985.4400105508, -2.5159493E-04, -1.5449073E-07, 7.2324505E-10, -2.9145404, 12.7093625336, 24499.7476701576, 8.3460748E-05, 3.1497443E-07, -1.5495082E-09, 2.7318890, 16.1258838235, 13799.8237756692, -4.3433786E-04, -3.7354477E-07, 1.8096592E-09,
-2.5679459, -2.4418059357, -7072.0875142282, -1.5764051E-04, -2.4917833E-07, 1.0774596E-09, -2.5211990, 7.9551277074, 8470.6667759558, -2.2382863E-04, -1.8523141E-07, 7.6873027E-10, 2.4888871, 5.6426988169, -486.3266040178, -3.7347750E-04, -4.3625891E-07, 2.0095091E-09, 2.1460741, 7.1842488353, -1952.4799803455, 6.4518350E-05, 7.3230428E-08, -2.9472308E-10,
1.9777270, 23.1494218585, 39414.2000050930, 1.9936508E-05, 3.7830496E-07, -1.8037978E-09, 1.9336825, 9.4222182890, 33314.7656989005, 6.0925100E-04, 1.0016445E-06, -4.7453563E-09, 1.8707647, 20.8369929680, 30457.2066251194, -1.2971236E-04, 1.2727746E-07, -5.6301898E-10, -1.7529659, 0.4873576771, -8886.0057043583, -3.3771956E-04, -4.6884877E-07, 2.2183135E-09,
-1.4371624, 7.0979974718, -695.8760698485, 5.9190587E-05, 7.4463212E-08, -4.0360254E-10, -1.3725701, 1.4552986550, -209.5494658307, 4.3266809E-04, 5.1072212E-07, -2.4131116E-09, 1.2618162, 7.5108957121, 16728.3705250656, 1.1655481E-04, 2.8300097E-07, -1.3951435E-09};
private static final double M11[] = {
1.6768000, -0.0431256817, 628.3019552485, -2.6638815E-06, 6.1639211E-10, -5.4439728E-11, 0.5164200, 11.2260974062, 6585.7609102104, -2.1583699E-04, -1.8708058E-07, 9.3204945E-10, 0.4138300, 13.5816519784, 14914.4523349355, -6.3524240E-05, 6.3330532E-08, -2.5428962E-10, 0.3711500, 5.5402729076, 7700.3894694766, 1.5497663E-04, 2.4979472E-07, -1.1318993E-09,
0.2756000, 2.3124288905, 8956.9933799736, 1.4964887E-04, 2.5102751E-07, -1.2407788E-09, 0.2459863, -25.6198212459, -2.3011998397, 1.5231275E-04, 2.5041111E-07, -1.1863391E-09, 0.0711800, 7.9982533891, 7842.3648207073, -2.2116475E-04, -1.8584780E-07, 8.2317000E-10, 0.0612800, 10.3538079614, 16171.0562454324, -6.8852003E-05, 6.4563317E-08, -3.6316908E-10};
private static final double M12[] = {0.0048700, -0.0431256817, 628.3019552485, -2.6638815E-06, 6.1639211E-10, -5.4439728E-11, 0.0022800, -27.1705318325, -2.3011998397, 1.5231275E-04, 2.5041111E-07, -1.1863391E-09, 0.0015000, 11.2260974062, 6585.7609102104, -2.1583699E-04, -1.8708058E-07, 9.3204945E-10};
private static final double M20[] = {
18461.2400600, 1.6279052448, 8433.4661576405, -6.4021295E-05, -4.9499477E-09, 2.0216731E-11, 1010.1671484, 3.9834598170, 16762.1575823656, 8.8291456E-05, 2.4546117E-07, -1.1661223E-09, 999.6936555, 0.7276493275, -104.7747329154, 2.1633405E-04, 2.5536106E-07, -1.2065558E-09, 623.6524746, 8.7690283983, 7109.2881325435, -2.1668263E-06, 6.8896872E-08, -3.2894608E-10,
199.4837596, 9.6692843156, 15647.5290230993, -2.8252217E-04, -1.9141414E-07, 8.9782646E-10, 166.5741153, 6.4134738261, -1219.4032921817, -1.5447958E-04, -1.8151424E-07, 8.5739300E-10, 117.2606951, 12.0248388879, 23976.2204478244, -1.3020942E-04, 5.8996977E-08, -2.8851262E-10, 61.9119504, 6.3390143893, 25090.8490070907, 2.4060421E-04, 4.9587228E-07, -2.3524614E-09,
33.3572027, 11.1245829706, 15437.9795572686, 1.5014592E-04, 3.1930799E-07, -1.5152852E-09, 31.7596709, 3.0832038997, 8223.9166918098, 3.6864680E-04, 5.0577218E-07, -2.3928949E-09, 29.5766003, 8.8121540801, 6480.9861772950, 4.9705523E-07, 6.8280480E-08, -2.7450635E-10, 15.5662654, 4.0579192538, -9548.0947169068, -3.0679233E-04, -4.3192536E-07, 2.0437321E-09,
15.1215543, 14.3803934601, 32304.9118725496, 2.2103334E-05, 3.0940809E-07, -1.4748517E-09, -12.0941511, 8.7259027166, 7737.5900877920, -4.8307078E-06, 6.9513264E-08, -3.8338581E-10, 8.8681426, 9.7124099974, 15019.2270678508, -2.7985829E-04, -1.9203053E-07, 9.5226618E-10, 8.0450400, 0.6687636586, 8399.7091105030, -3.3191993E-05, 3.2017096E-08, -1.5363746E-10,
7.9585542, 12.0679645696, 23347.9184925760, -1.2754553E-04, 5.8380585E-08, -2.3407289E-10, 7.4345550, 6.4565995078, -1847.7052474301, -1.5181570E-04, -1.8213063E-07, 9.1183272E-10, -6.7314363, -4.0265854988, -16133.8556271171, -9.0955337E-05, -2.4484477E-07, 1.1116826E-09, 6.5795750, 16.8104074692, 14323.3509980023, -2.2066770E-04, -1.1756732E-07, 5.4866364E-10,
-6.4600721, 1.5847795630, 9061.7681128890, -6.6685176E-05, -4.3335556E-09, -3.4222998E-11, -6.2964773, 4.8837157343, 25300.3984729215, -1.9206388E-04, -1.4849843E-08, 6.0650192E-11, -5.6323538, -0.7707750092, 733.0766881638, -2.1899793E-04, -2.5474467E-07, 1.1521161E-09, -5.3683961, 6.8263720663, 16204.8433027325, -9.7115356E-05, 2.7023515E-08, -1.3414795E-10,
-5.3112784, 3.9403341353, 17390.4595376141, 8.5627574E-05, 2.4607756E-07, -1.2205621E-09, -5.0759179, 0.6845236457, 523.5272223331, 2.1367016E-04, 2.5597745E-07, -1.2609955E-09, -4.8396143, -1.6710309265, -7805.1642023920, 6.1357413E-05, 5.5663398E-09, -7.4656459E-11, -4.8057401, 3.5705615768, -662.0890125485, 3.0927234E-05, 3.6923410E-08, -1.7458141E-10,
3.9840545, 8.6945689615, 33419.5404318159, 3.9291696E-04, 7.4628340E-07, -3.5388005E-09, 3.6744619, 19.1659620415, 22652.0424227274, -6.8354947E-05, 1.3284380E-07, -6.3767543E-10, 2.9984815, 20.0662179587, 31190.2833132833, -3.4871029E-04, -1.2746721E-07, 5.8909710E-10, 2.7986413, -2.5281611620, -16971.7070481963, 3.4437664E-04, 2.6526096E-07, -1.2469893E-09,
2.4138774, 17.7106633865, 22861.5918885581, -5.0102304E-04, -3.7787833E-07, 1.7754362E-09, 2.1863132, 5.5132179088, -9757.6441827375, 1.2587576E-04, 7.8796768E-08, -3.6937954E-10, 2.1461692, 13.4801375428, 23766.6709819937, 3.0245868E-04, 5.6971910E-07, -2.7016242E-09, 1.7659832, 11.1677086523, 14809.6776020201, 1.5280981E-04, 3.1869159E-07, -1.4608454E-09,
-1.6244212, 7.3137297434, 7318.8375983742, -4.3483492E-04, -4.4182525E-07, 2.0841655E-09, 1.5813036, 5.4387584720, 16552.6081165349, 5.2095955E-04, 7.5618329E-07, -3.5792340E-09, 1.5197528, 16.7359480324, 40633.6032972747, 1.7441609E-04, 5.5981921E-07, -2.6611908E-09, 1.5156341, 1.7023646816, -17876.7861416319, -4.5910508E-04, -6.8233647E-07, 3.2300712E-09,
1.5102092, 5.4977296450, 8399.6847301375, -3.3094061E-05, 3.1973462E-08, -1.5436468E-10, -1.3178223, 9.6261586339, 16275.8309783478, -2.8518605E-04, -1.9079775E-07, 8.4338673E-10, -1.2642739, 11.9817132061, 24604.5224030729, -1.3287330E-04, 5.9613369E-08, -3.4295235E-10, 1.1918723, 22.4217725310, 39518.9747380084, -1.9639754E-04, 1.2294390E-07, -5.9724197E-10,
1.1346110, 14.4235191419, 31676.6099173011, 2.4767216E-05, 3.0879170E-07, -1.4204120E-09, 1.0857810, 8.8552797618, 5852.6842220465, 3.1609367E-06, 6.7664088E-08, -2.2006663E-10, -1.0193852, 7.2392703065, 33629.0898976466, -3.9751134E-05, 2.3556127E-07, -1.1256889E-09, -0.8227141, 11.0814572888, 16066.2815125171, 1.4748204E-04, 3.1992438E-07, -1.5697249E-09,
0.8042238, 3.5274358950, -33.7870573000, 2.8263353E-05, 3.7539802E-08, -2.2902113E-10, 0.8025939, 6.7832463846, 16833.1452579809, -9.9779237E-05, 2.7639907E-08, -1.8858767E-10, -0.7931866, -6.3821400710, -24462.5470518423, -2.4326809E-04, -4.9525589E-07, 2.2980217E-09, -0.7910153, 6.3703481443, -591.1013369332, -1.5714346E-04, -1.8089785E-07, 8.0295327E-10,
-0.6674056, 9.1819266386, 24533.5347274576, 5.5197395E-05, 2.7743463E-07, -1.3204870E-09, 0.6502226, 4.1010449356, -10176.3966721553, -3.0412845E-04, -4.3254175E-07, 2.0981718E-09, -0.6388131, 6.2958887075, 25719.1509623392, 2.3794032E-04, 4.9648867E-07, -2.4069012E-09};
private static final double M21[] = {
0.0743000, 11.9537467337, 6480.9861772950, 4.9705523E-07, 6.8280480E-08, -2.7450635E-10, 0.0304300, 8.7259027166, 7737.5900877920, -4.8307078E-06, 6.9513264E-08, -3.8338581E-10, 0.0222900, 12.8540026510, 15019.2270678508, -2.7985829E-04, -1.9203053E-07, 9.5226618E-10, 0.0199900, 15.2095572232, 23347.9184925760, -1.2754553E-04, 5.8380585E-08, -2.3407289E-10,
0.0186900, 9.5981921614, -1847.7052474301, -1.5181570E-04, -1.8213063E-07, 9.1183272E-10, 0.0169600, 7.1681781524, 16133.8556271171, 9.0955337E-05, 2.4484477E-07, -1.1116826E-09, 0.0162300, 1.5847795630, 9061.7681128890, -6.6685176E-05, -4.3335556E-09, -3.4222998E-11, 0.0141900, -0.7707750092, 733.0766881638, -2.1899793E-04, -2.5474467E-07, 1.1521161E-09};
private static final double M30[] = {
385000.5290396, 1.5707963268, 0.0000000000, 0.0000000E+00, 0.0000000E+00, 0.0000000E+00, -20905.3551378, 3.9263508990, 8328.6914247251, 1.5231275E-04, 2.5041111E-07, -1.1863391E-09, -3699.1109330, 9.6121753977, 7214.0628654588, -2.1850087E-04, -1.8646419E-07, 8.7760973E-10, -2955.9675626, 11.9677299699, 15542.7542901840, -6.6188121E-05, 6.3946925E-08, -3.0872935E-10,
-569.9251264, 6.2819054713, 16657.3828494503, 3.0462550E-04, 5.0082223E-07, -2.3726782E-09, 246.1584797, 7.2566208254, -1114.6285592663, -3.7081362E-04, -4.3687530E-07, 2.0639488E-09, -204.5861179, 12.0108556517, 14914.4523349355, -6.3524240E-05, 6.3330532E-08, -2.5428962E-10, -170.7330791, 14.3232845422, 23871.4457149091, 8.6124629E-05, 3.1435804E-07, -1.4950684E-09,
-152.1378118, 9.6553010794, 6585.7609102104, -2.1583699E-04, -1.8708058E-07, 9.3204945E-10, -129.6202242, -0.8278839272, -7700.3894694766, -1.5497663E-04, -2.4979472E-07, 1.1318993E-09, 108.7427014, 6.7692631483, 7771.3771450920, -3.3094061E-05, 3.1973462E-08, -1.5436468E-10, 104.7552944, 3.8832252173, 8956.9933799736, 1.4964887E-04, 2.5102751E-07, -1.2407788E-09,
79.6605685, 0.6705404095, -8538.2408905558, 2.8035534E-04, 2.6031101E-07, -1.2267725E-09, 48.8883284, 1.5276706450, 628.3019552485, -2.6638815E-06, 6.1639211E-10, -5.4439728E-11, -34.7825237, 20.0091090408, 22756.8171556428, -2.8468899E-04, -1.2251727E-07, 5.6888037E-10, 30.8238599, 11.9246042882, 16171.0562454324, -6.8852003E-05, 6.4563317E-08, -3.6316908E-10,
24.2084985, 9.5690497159, 7842.3648207073, -2.2116475E-04, -1.8584780E-07, 8.2317000E-10, -23.2104305, 8.6374600436, 24986.0742741754, 4.5693825E-04, 7.5123334E-07, -3.5590172E-09, -21.6363439, 17.6535544685, 14428.1257309177, -4.3700174E-04, -3.7292838E-07, 1.7552195E-09, -16.6747239, 6.7261374666, 8399.6791003405, -3.5757942E-05, 3.2589854E-08, -2.0880440E-10,
14.4026890, 4.9010662531, -9443.3199839914, -5.2312637E-04, -6.8728642E-07, 3.2502879E-09, -12.8314035, 14.3664102239, 23243.1437596606, 8.8788511E-05, 3.1374165E-07, -1.4406287E-09, -11.6499478, 22.3646636130, 31085.5085803679, -1.3237624E-04, 1.2789385E-07, -6.1745870E-10, -10.4447578, 16.6788391144, 32200.1371396342, 2.3843738E-04, 5.6476915E-07, -2.6814075E-09,
10.3211071, 8.7119194804, -1324.1780250970, 6.1854469E-05, 7.3846820E-08, -3.4916281E-10, 10.0562033, 7.2997465071, -1742.9305145148, -3.6814974E-04, -4.3749170E-07, 2.1183885E-09, -9.8844667, 12.0539813334, 14286.1503796870, -6.0860358E-05, 6.2714140E-08, -1.9984990E-10, 8.7515625, 6.3563649081, -9652.8694498221, -9.0458282E-05, -1.7656429E-07, 8.3717626E-10,
-8.3791067, 4.4137085761, -557.3142796331, -1.8540681E-04, -2.1843765E-07, 1.0319744E-09, -7.0026961, -3.1834384995, -16029.0808942018, -3.0728938E-04, -5.0020584E-07, 2.3182384E-09, 6.3220032, 9.1248177206, 16100.0685698171, 1.1921869E-04, 2.8238458E-07, -1.3407038E-09, 5.7508579, 6.2387797896, 17285.6848046987, 3.0196162E-04, 5.0143862E-07, -2.4271179E-09,
-4.9501349, 9.6984267611, 5957.4589549619, -2.1317311E-04, -1.8769697E-07, 9.8648918E-10, -4.4211770, 3.0260949818, -209.5494658307, 4.3266809E-04, 5.1072212E-07, -2.4131116E-09, 4.1311145, 11.0674740526, 7004.5133996281, 2.1416722E-04, 3.2425793E-07, -1.5355019E-09, -3.9579827, 20.0522347225, 22128.5152003943, -2.8202511E-04, -1.2313366E-07, 6.2332010E-10,
3.2582371, 14.8106422192, 14985.4400105508, -2.5159493E-04, -1.5449073E-07, 7.2324505E-10, -3.1483020, 4.8266068163, 16866.9323152810, -1.2804259E-04, -9.8998954E-09, 4.0433461E-11, 2.6164092, 14.2801588604, 24499.7476701576, 8.3460748E-05, 3.1497443E-07, -1.5495082E-09, 2.3536310, 9.5259240342, 8470.6667759558, -2.2382863E-04, -1.8523141E-07, 7.6873027E-10,
-2.1171283, -0.8710096090, -7072.0875142282, -1.5764051E-04, -2.4917833E-07, 1.0774596E-09, -1.8970368, 17.6966801503, 13799.8237756692, -4.3433786E-04, -3.7354477E-07, 1.8096592E-09, -1.7385258, 2.0581540038, -8886.0057043583, -3.3771956E-04, -4.6884877E-07, 2.2183135E-09, -1.5713944, 22.4077892948, 30457.2066251194, -1.2971236E-04, 1.2727746E-07, -5.6301898E-10,
-1.4225541, 24.7202181853, 39414.2000050930, 1.9936508E-05, 3.7830496E-07, -1.8037978E-09, -1.4189284, 17.1661967915, 23314.1314352759, -9.9282182E-05, 9.5920387E-08, -4.6309403E-10, 1.1655364, 3.8400995356, 9585.2953352221, 1.4698499E-04, 2.5164390E-07, -1.2952185E-09, -1.1169371, 10.9930146158, 33314.7656989005, 6.0925100E-04, 1.0016445E-06, -4.7453563E-09,
1.0656723, 1.4845449633, 1256.6039104970, -5.3277630E-06, 1.2327842E-09, -1.0887946E-10, 1.0586190, 11.9220903668, 8364.7398411275, -2.1850087E-04, -1.8646419E-07, 8.7760973E-10, -0.9333176, 9.0816920389, 16728.3705250656, 1.1655481E-04, 2.8300097E-07, -1.3951435E-09, 0.8624328, 12.4550876470, 6656.7485858257, -4.0390768E-04, -4.0490184E-07, 1.9095841E-09,
0.8512404, 4.3705828944, 70.9876756153, -1.8807069E-04, -2.1782126E-07, 9.7753467E-10, -0.8488018, 16.7219647962, 31571.8351843857, 2.4110126E-04, 5.6415276E-07, -2.6269678E-09, -0.7956264, 3.5134526588, -9095.5551701890, 9.4948529E-05, 4.1873358E-08, -1.9479814E-10};
private static final double M31[] = {
0.5139500, 12.0108556517, 14914.4523349355, -6.3524240E-05, 6.3330532E-08, -2.5428962E-10, 0.3824500, 9.6553010794, 6585.7609102104, -2.1583699E-04, -1.8708058E-07, 9.3204945E-10, 0.3265400, 3.9694765808, 7700.3894694766, 1.5497663E-04, 2.4979472E-07, -1.1318993E-09, 0.2639600, 0.7416325637, 8956.9933799736, 1.4964887E-04, 2.5102751E-07, -1.2407788E-09,
0.1230200, -1.6139220085, 628.3019552485, -2.6638815E-06, 6.1639211E-10, -5.4439728E-11, 0.0775400, 8.7830116346, 16171.0562454324, -6.8852003E-05, 6.4563317E-08, -3.6316908E-10, 0.0606800, 6.4274570623, 7842.3648207073, -2.2116475E-04, -1.8584780E-07, 8.2317000E-10, 0.0497000, 12.0539813334, 14286.1503796870, -6.0860358E-05, 6.2714140E-08, -1.9984990E-10};
private static final double M1n[] = {3.81034392032, 8.39968473021E+03, -3.31919929753E-05, //月球平黄经系数
3.20170955005E-08, -1.53637455544E-10};
private static double EnnT = 0; // 调用Enn前先设置EnnT时间变量
/**
* 计算E10,E11,E20等,即:某一组周期项或泊松项算出,计算前先设置EnnT时间
*
* @param F F
* @return 计算E10, E11, E20等
*/
private static double Enn(double[] F) {
double v = 0;
for (int i = 0; i < F.length; i += 3)
v += F[i] * Math.cos(F[i + 1] + EnnT * F[i + 2]);
return v;
}
/**
* 返回地球位置,日心Date黄道分点坐标
*
* @param jd jd
* @return 返回地球位置, 日心Date黄道分点坐标
*/
private static double[] earCal(double jd) {
EnnT = jd / 365250;
double llr[] = new double[3];
double t1 = EnnT, t2 = t1 * t1, t3 = t2 * t1, t4 = t3 * t1, t5 = t4
* t1;
llr[0] = Enn(E10) + Enn(E11) * t1 + Enn(E12) * t2 + Enn(E13) * t3
+ Enn(E14) * t4 + Enn(E15) * t5;
llr[1] = Enn(E20) + Enn(E21) * t1;
llr[2] = Enn(E30) + Enn(E31) * t1 + Enn(E32) * t2 + Enn(E33) * t3;
llr[0] = rad2mrad(llr[0]);
return llr;
}
// ==================月位置计算===================
private static double MnnT = 0; // 调用Mnn前先设置MnnT时间变量
/**
* 计算M10,M11,M20等,计算前先设置MnnT时间
*
* @param F F
* @return 计算M10, M11, M20等, 计算前先设置MnnT时间
*/
private static double Mnn(double[] F) {
double v = 0, t1 = MnnT, t2 = t1 * t1, t3 = t2 * t1, t4 = t3 * t1;
for (int i = 0; i < F.length; i += 6)
v += F[i]
* Math.sin(F[i + 1] + t1 * F[i + 2] + t2 * F[i + 3] + t3
* F[i + 4] + t4 * F[i + 5]);
return v;
}
/**
* 返回月球位置,返回地心Date黄道坐标
*
* @param julian 儒略历
* @return return 地心黄道坐标
*/
private static double[] moonCoord(double julian) {
MnnT = julian / 36525;
double t1 = MnnT, t2 = t1 * t1, t3 = t2 * t1, t4 = t3 * t1;
double[] llr = new double[3];
llr[0] = (Mnn(M10) + Mnn(M11) * t1 + Mnn(M12) * t2) / SECOND_PER_RAD;
llr[1] = (Mnn(M20) + Mnn(M21) * t1) / SECOND_PER_RAD;
llr[2] = (Mnn(M30) + Mnn(M31) * t1) * 0.999999949827;
llr[0] = llr[0] + M1n[0] + M1n[1] * t1 + M1n[2] * t2 + M1n[3] * t3
+ M1n[4] * t4;
llr[0] = rad2mrad(llr[0]); // 地心Date黄道原点坐标(不含岁差)
precession(julian, llr); // 补岁差
return llr;
}
/**
* 地心坐标中的日月位置计算
*
* @param lx lx=1时计算t时刻日月角距与jiao的差, lx=0计算t时刻太阳黄经与jiao的差
* @param time time
* @param angle angle
* @return 地心坐标中的日月位置计算
*/
private static double angleDiff(int lx, double time, double angle) {
double[] sun = earCal(time); // 计算太阳真位置(先算出日心坐标中地球的位置)
sun[0] += Math.PI;
sun[1] = -sun[1]; // 转为地心坐标
addGxc(time, sun); // 补周年光行差
if (lx == 0) {
Nutation d = nutation(time);
sun[0] += d.Lon; // 补黄经章动
return rad2mrad(angle - sun[0]);
}
double[] moon = moonCoord(time); // 日月角差与章动无关
return rad2mrad(angle - (moon[0] - sun[0]));
}
/**
* 已知位置反求时间,对于节气计算,应满足t在t1到t1+360天之间,对于Y年第n个节气(n=0是春分),t1可取值Y*365.2422+n*15.2,
* 对于朔望计算,应满足t在t1到t1+25天之间,在此范围之外,求右边的根
*
* @param t1 J2000起算儒略日数,传入的t1是指定角度对应真时刻t的前一些天
* @param angle 已知角度(jiao)求时间(t)
* @param lx lx=0是太阳黄经达某角度的时刻计算(用于节气计算)
* lx=1是日月角距达某角度的时刻计算(用于定朔望等)
* @return 已知位置反求时间
*/
private static double getTimeFromAngle(double t1, double angle, int lx) {
double t2 = t1, t = 0, v;
if (lx == 0)
t2 += 360; // 在t1到t2范围内求解(范气360天范围),结果置于t
else
t2 += 25;
angle *= Math.PI / 180; // 待搜索目标角
// 利用截弦法计算
double v1 = angleDiff(lx, t1, angle); // v1,v2为t1,t2时对应的黄经
double v2 = angleDiff(lx, t2, angle);
if (v1 < v2)
v2 -= 2 * Math.PI; // 减2pi作用是将周期性角度转为连续角度
double k = 1, k2; // k是截弦的斜率
for (int i = 0; i < 10; i++) { // 快速截弦求根,通常截弦三四次就已达所需精度
k2 = (v2 - v1) / (t2 - t1); // 算出斜率
if (Math.abs(k2) > 1e-15)
k = k2; // 差商可能为零,应排除
t = t1 - v1 / k;
v = angleDiff(lx, t, angle);// 直线逼近法求根(直线方程的根)
if (v > 1)
v -= 2 * Math.PI; // 一次逼近后,v1就已接近0,如果很大,则应减1周
if (Math.abs(v) < 1e-8)
break; // 已达精度
t1 = t2;
v1 = v2;
t2 = t;
v2 = v; // 下一次截弦
}
return t;
}
/**
* 获得某一年24节气
*
* @param year 年
* @return 24节气
*/
public static String[] getSolarTerms(int year) {
String[] solarTerms = new String[24];
String[] preOffset = getSolarTermsPreOffset(year - 1);
String[] nextOffset = getSolarTermsNextOffset(year - 1);
System.arraycopy(preOffset, 0, solarTerms, 0, preOffset.length);
System.arraycopy(nextOffset, 0, solarTerms, 22, nextOffset.length);
double jd = 365.2422 * (year - 2000), q;
for (int i = 0; i < 19; i++) {
q = getTimeFromAngle(jd + i * 15.2, i * 15, 0);
q = q + J2000 + (double) 8 / 24; // 计算第i个节气(i=0是春分),结果转为北京时
Time time = setFromJulian(q, true);
solarTerms[i + 3] = time.toString() + SOLAR_TERMS[i];
}
return solarTerms;
}
/**
* 要获得2018年24节气需要传入2017年
*
* @param year 要获得2018年24节气需要传入2017年
* @return 返回 立春 雨水 惊蛰
*/
private static String[] getSolarTermsPreOffset(int year) {
String[] solarTerms = new String[3];
double jd = 365.2422 * (year - 2000), q;
for (int i = 21; i < 24; i++) {
q = getTimeFromAngle(jd + i * 15.2, i * 15, 0);
q = q + J2000 + (double) 8 / 24; // 计算第i个节气(i=0是春分)
Time time = setFromJulian(q, true);
solarTerms[i - 21] = time.toString() + SOLAR_TERMS[i];
}
return solarTerms;
}
/**
* 要获得2018年24节气需要传入2017年
*
* @param year 要获得2018年24节气需要传入2017年
* @return 返回 小寒大寒
*/
private static String[] getSolarTermsNextOffset(int year) {
String[] solarTerms = new String[2];
double jd = 365.2422 * (year - 2000), q;
for (int i = 19; i < 21; i++) {
q = getTimeFromAngle(jd + i * 15.2, i * 15, 0);
q = q + J2000 + (double) 8 / 24; // 计算第i个节气(i=0是春分)
Time time = setFromJulian(q, true);
solarTerms[i - 19] = time.toString() + SOLAR_TERMS[i];
}
return solarTerms;
}
/**
* 章动
*/
private static class Nutation {
/**
* 章动角
*/
private double Lon;
/**
* 交角
*/
private double Obl;
}
private static class Time {
private double year;
private double month;
private double day;
private double hour;
private double minute;
private double second;
@Override
public String toString() {
return doubleToString(year) + doubleToString(month) + doubleToString(day);
}
}
private static String doubleToString(double value) {
int v = (int) value;
return value < 10 ? "0" + v : String.valueOf(v);
}
}
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import com.sobot.widget.R;
/**
* 干支纪年算法
*/
@SuppressWarnings("unused")
public final class TrunkBranchAnnals {
/**
* 天干字符串
*/
private static String[] TRUNK_STR = null;
/**
* 地支字符串
*/
private static String[] BRANCH_STR = null;
/**
* 单独使用请先调用这个方法
* @param context context
*/
public static void init(Context context) {
if (TRUNK_STR != null) {
return;
}
TRUNK_STR = context.getResources().getStringArray(R.array.trunk_string_array);
BRANCH_STR = context.getResources().getStringArray(R.array.branch_string_array);
}
/**
* 获取某一年对应天干文字
*
* @param year 年份
* @return 天干由甲到癸,每10一轮回
*/
@SuppressWarnings("all")
public static String getTrunkString(int year) {
return TRUNK_STR[getTrunkInt(year)];
}
/**
* 获取某一年对应天干,
*
* @param year 年份
* @return 4 5 6 7 8 9 10 1 2 3
*/
@SuppressWarnings("all")
public static int getTrunkInt(int year) {
int trunk = year % 10;
return trunk == 0 ? 9 : trunk - 1;
}
/**
* 获取某一年对应地支文字
*
* @param year 年份
* @return 地支由子到亥,每12一轮回
*/
@SuppressWarnings("all")
public static String getBranchString(int year) {
return BRANCH_STR[getBranchInt(year)];
}
/**
* 获取某一年对应地支
*
* @param year 年份
* @return 4 5 6 7 8 9 10 11 12 1 2 3
*/
@SuppressWarnings("all")
public static int getBranchInt(int year) {
int branch = year % 12;
return branch == 0 ? 11 : branch - 1;
}
/**
* 获取干支纪年
*
* @param year 年份
* @return 干支纪年
*/
public static String getTrunkBranchYear(int year) {
return String.format("%s%s", getTrunkString(year), getBranchString(year));
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.sobot.widget.R;
/**
* 星期栏,如果你要使用星期栏自定义,切记XML使用 merge,不要使用LinearLayout
*/
public class WeekBar extends LinearLayout {
private CalendarViewDelegate mDelegate;
public WeekBar(Context context) {
super(context);
if ("com.haibin.calendarview.WeekBar".equals(getClass().getName())) {
LayoutInflater.from(context).inflate(R.layout.sobot_week_bar, this, true);
}
}
/**
* 传递属性
*
* @param delegate delegate
*/
void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
if ("com.haibin.calendarview.WeekBar".equalsIgnoreCase(getClass().getName())) {
setTextSize(mDelegate.getWeekTextSize());
setTextColor(delegate.getWeekTextColor());
setBackgroundColor(delegate.getWeekBackground());
setPadding(delegate.getCalendarPaddingLeft(), 0, delegate.getCalendarPaddingRight(), 0);
}
}
/**
* 设置文本颜色,使用自定义布局需要重写这个方法,避免出问题
* 如果这里报错了,请确定你自定义XML文件跟布局是不是使用merge,而不是LinearLayout
*
* @param color color
*/
protected void setTextColor(int color) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setTextColor(color);
}
}
/**
* 设置文本大小
*
* @param size size
*/
protected void setTextSize(int size) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}
}
/**
* 日期选择事件,这里提供这个回调,可以方便定制WeekBar需要
*
* @param calendar calendar 选择的日期
* @param weekStart 周起始
* @param isClick isClick 点击
*/
protected void onDateSelected(Calendar calendar, int weekStart, boolean isClick) {
}
/**
* 当周起始发生变化,使用自定义布局需要重写这个方法,避免出问题
*
* @param weekStart 周起始
*/
protected void onWeekStartChange(int weekStart) {
if (!"com.haibin.calendarview.WeekBar".equalsIgnoreCase(getClass().getName())) {
return;
}
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setText(getWeekString(i, weekStart));
}
}
/**
* 通过View的位置和周起始获取星期的对应坐标
*
* @param calendar calendar
* @param weekStart weekStart
* @return 通过View的位置和周起始获取星期的对应坐标
*/
protected int getViewIndexByCalendar(Calendar calendar, int weekStart) {
int week = calendar.getWeek() + 1;
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_SUN) {
return week - 1;
}
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_MON) {
return week == CalendarViewDelegate.WEEK_START_WITH_SUN ? 6 : week - 2;
}
return week == CalendarViewDelegate.WEEK_START_WITH_SAT ? 0 : week;
}
/**
* 或者周文本,这个方法仅供父类使用
*
* @param index index
* @param weekStart weekStart
* @return 或者周文本
*/
private String getWeekString(int index, int weekStart) {
String[] weeks = getContext().getResources().getStringArray(R.array.week_string_array);
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_SUN) {
return weeks[index];
}
if (weekStart == CalendarViewDelegate.WEEK_START_WITH_MON) {
return weeks[index == 6 ? 0 : index + 1];
}
return weeks[index == 0 ? 6 : index - 1];
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mDelegate != null) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mDelegate.getWeekBarHeight(), MeasureSpec.EXACTLY);
} else {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(CalendarUtil.dipToPx(getContext(), 40), MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
/**
* 周视图,因为日历UI采用热插拔实现,所以这里必须继承实现,达到UI一致即可
*/
public abstract class WeekView extends BaseWeekView {
public WeekView(Context context) {
super(context);
}
/**
* 绘制日历文本
*
* @param canvas canvas
*/
@Override
protected void onDraw(Canvas canvas) {
if (mItems.size() == 0)
return;
mItemWidth = (getWidth() -
mDelegate.getCalendarPaddingLeft() -
mDelegate.getCalendarPaddingRight()) / 7;
onPreviewHook();
for (int i = 0; i < mItems.size(); i++) {
int x = i * mItemWidth + mDelegate.getCalendarPaddingLeft();
onLoopStart(x);
Calendar calendar = mItems.get(i);
boolean isSelected = i == mCurrentItem;
boolean hasScheme = calendar.hasScheme();
if (hasScheme) {
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, true);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ?
calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, false);
}
}
onDrawText(canvas, calendar, x, hasScheme, isSelected);
}
}
@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Calendar calendar = getIndex();
if (calendar == null) {
return;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return;
}
if (!isInRange(calendar)) {
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarOutOfRange(calendar);
}
return;
}
mCurrentItem = mItems.indexOf(calendar);
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, true);
}
if (mParentLayout != null) {
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, true);
}
invalidate();
}
@Override
public boolean onLongClick(View v) {
if (mDelegate.mCalendarLongClickListener == null)
return false;
if (!isClick) {
return false;
}
Calendar calendar = getIndex();
if (calendar == null) {
return false;
}
if (onCalendarIntercept(calendar)) {
mDelegate.mCalendarInterceptListener.onCalendarInterceptClick(calendar, true);
return true;
}
boolean isCalendarInRange = isInRange(calendar);
if (!isCalendarInRange) {
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClickOutOfRange(calendar);
}
return true;
}
if (mDelegate.isPreventLongPressedSelected()) {//如果启用拦截长按事件不选择日期
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClick(calendar);
}
return true;
}
mCurrentItem = mItems.indexOf(calendar);
mDelegate.mIndexCalendar = mDelegate.mSelectedCalendar;
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, true);
}
if (mParentLayout != null) {
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, true);
}
if (mDelegate.mCalendarLongClickListener != null) {
mDelegate.mCalendarLongClickListener.onCalendarLongClick(calendar);
}
invalidate();
return true;
}
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return 是否绘制 onDrawScheme
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme);
/**
* 绘制标记的日期
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import java.lang.reflect.Constructor;
import java.util.List;
/**
* 周视图滑动ViewPager,需要动态固定高度
* 周视图是连续不断的视图,因此不能简单的得出每年都有52+1周,这样会计算重叠的部分
* WeekViewPager需要和CalendarView关联:
*/
public final class WeekViewPager extends ViewPager {
private boolean isUpdateWeekView;
private int mWeekCount;
private CalendarViewDelegate mDelegate;
/**
* 日历布局,需要在日历下方放自己的布局
*/
CalendarLayout mParentLayout;
/**
* 是否使用滚动到某一天
*/
private boolean isUsingScrollToCalendar = false;
public WeekViewPager(Context context) {
this(context, null);
}
public WeekViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
init();
}
private void init() {
mWeekCount = CalendarUtil.getWeekCountBetweenBothCalendar(
mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
mDelegate.getMaxYear(),
mDelegate.getMaxYearMonth(),
mDelegate.getMaxYearDay(),
mDelegate.getWeekStart());
setAdapter(new WeekViewPagerAdapter());
addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//默认的显示星期四,周视图切换就显示星期4
if (getVisibility() != VISIBLE) {
isUsingScrollToCalendar = false;
return;
}
if (isUsingScrollToCalendar) {
isUsingScrollToCalendar = false;
return;
}
BaseWeekView view = findViewWithTag(position);
if (view != null) {
view.performClickCalendar(mDelegate.getSelectMode() != CalendarViewDelegate.SELECT_MODE_DEFAULT ?
mDelegate.mIndexCalendar : mDelegate.mSelectedCalendar, !isUsingScrollToCalendar);
if (mDelegate.mWeekChangeListener != null) {
mDelegate.mWeekChangeListener.onWeekChange(getCurrentWeekCalendars());
}
}
isUsingScrollToCalendar = false;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* 获取当前周数据
*
* @return 获取当前周数据
*/
List<Calendar> getCurrentWeekCalendars() {
List<Calendar> calendars = CalendarUtil.getWeekCalendars(mDelegate.mIndexCalendar,
mDelegate);
mDelegate.addSchemesFromMap(calendars);
return calendars;
}
/**
* 更新周视图
*/
void notifyDataSetChanged() {
mWeekCount = CalendarUtil.getWeekCountBetweenBothCalendar(
mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
mDelegate.getMaxYear(),
mDelegate.getMaxYearMonth(),
mDelegate.getMaxYearDay(),
mDelegate.getWeekStart());
notifyAdapterDataSetChanged();
}
/**
* 更新周视图布局
*/
void updateWeekViewClass() {
isUpdateWeekView = true;
notifyAdapterDataSetChanged();
isUpdateWeekView = false;
}
/**
* 更新日期范围
*/
void updateRange() {
isUpdateWeekView = true;
notifyDataSetChanged();
isUpdateWeekView = false;
if (getVisibility() != VISIBLE) {
return;
}
isUsingScrollToCalendar = true;
Calendar calendar = mDelegate.mSelectedCalendar;
updateSelected(calendar, false);
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, false);
}
if (mDelegate.mCalendarSelectListener != null) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, false);
}
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
/**
* 滚动到指定日期
*
* @param year 年
* @param month 月
* @param day 日
* @param invokeListener 调用日期事件
*/
void scrollToCalendar(int year, int month, int day, boolean smoothScroll, boolean invokeListener) {
isUsingScrollToCalendar = true;
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setCurrentDay(calendar.equals(mDelegate.getCurrentDay()));
LunarCalendar.setupLunarCalendar(calendar);
mDelegate.mIndexCalendar = calendar;
mDelegate.mSelectedCalendar = calendar;
mDelegate.updateSelectCalendarScheme();
updateSelected(calendar, smoothScroll);
if (mDelegate.mInnerListener != null) {
mDelegate.mInnerListener.onWeekDateSelected(calendar, false);
}
if (mDelegate.mCalendarSelectListener != null && invokeListener) {
mDelegate.mCalendarSelectListener.onCalendarSelect(calendar, false);
}
int i = CalendarUtil.getWeekFromDayInMonth(calendar, mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
/**
* 滚动到当前
*/
void scrollToCurrent(boolean smoothScroll) {
isUsingScrollToCalendar = true;
int position = CalendarUtil.getWeekFromCalendarStartWithMinCalendar(mDelegate.getCurrentDay(),
mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
mDelegate.getWeekStart()) - 1;
int curItem = getCurrentItem();
if (curItem == position) {
isUsingScrollToCalendar = false;
}
setCurrentItem(position, smoothScroll);
BaseWeekView view = findViewWithTag(position);
if (view != null) {
view.performClickCalendar(mDelegate.getCurrentDay(), false);
view.setSelectedCalendar(mDelegate.getCurrentDay());
view.invalidate();
}
if (mDelegate.mCalendarSelectListener != null && getVisibility() == VISIBLE) {
mDelegate.mCalendarSelectListener.onCalendarSelect(mDelegate.mSelectedCalendar, false);
}
if (getVisibility() == VISIBLE) {
mDelegate.mInnerListener.onWeekDateSelected(mDelegate.getCurrentDay(), false);
}
int i = CalendarUtil.getWeekFromDayInMonth(mDelegate.getCurrentDay(), mDelegate.getWeekStart());
mParentLayout.updateSelectWeek(i);
}
/**
* 更新任意一个选择的日期
*/
void updateSelected(Calendar calendar, boolean smoothScroll) {
int position = CalendarUtil.getWeekFromCalendarStartWithMinCalendar(calendar,
mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
mDelegate.getWeekStart()) - 1;
int curItem = getCurrentItem();
isUsingScrollToCalendar = curItem != position;
setCurrentItem(position, smoothScroll);
BaseWeekView view = findViewWithTag(position);
if (view != null) {
view.setSelectedCalendar(calendar);
view.invalidate();
}
}
/**
* 更新单选模式
*/
void updateSingleSelect() {
if (mDelegate.getSelectMode() == CalendarViewDelegate.SELECT_MODE_DEFAULT) {
return;
}
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateSingleSelect();
}
}
/**
* 更新为默认选择模式
*/
void updateDefaultSelect() {
BaseWeekView view = findViewWithTag(getCurrentItem());
if (view != null) {
view.setSelectedCalendar(mDelegate.mSelectedCalendar);
view.invalidate();
}
}
/**
* 更新选择效果
*/
void updateSelected() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.setSelectedCalendar(mDelegate.mSelectedCalendar);
view.invalidate();
}
}
/**
* 更新字体颜色大小
*/
final void updateStyle() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateStyle();
view.invalidate();
}
}
/**
* 更新标记日期
*/
void updateScheme() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.update();
}
}
/**
* 更新当前日期,夜间过度的时候调用这个函数,一般不需要调用
*/
void updateCurrentDate() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateCurrentDate();
}
}
/**
* 更新显示模式
*/
void updateShowMode() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateShowMode();
}
}
/**
* 更新周起始
*/
void updateWeekStart() {
if (getAdapter() == null) {
return;
}
int count = getAdapter().getCount();
mWeekCount = CalendarUtil.getWeekCountBetweenBothCalendar(
mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
mDelegate.getMaxYear(),
mDelegate.getMaxYearMonth(),
mDelegate.getMaxYearDay(),
mDelegate.getWeekStart());
/*
* 如果count发生变化,意味着数据源变化,则必须先调用notifyDataSetChanged(),
* 否则会抛出异常
*/
if (count != mWeekCount) {
isUpdateWeekView = true;
getAdapter().notifyDataSetChanged();
}
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateWeekStart();
}
isUpdateWeekView = false;
updateSelected(mDelegate.mSelectedCalendar, false);
}
/**
* 更新高度
*/
final void updateItemHeight() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.updateItemHeight();
view.requestLayout();
}
}
/**
* 清除选择范围
*/
final void clearSelectRange() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.invalidate();
}
}
final void clearSingleSelect() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.mCurrentItem = -1;
view.invalidate();
}
}
final void clearMultiSelect() {
for (int i = 0; i < getChildCount(); i++) {
BaseWeekView view = (BaseWeekView) getChildAt(i);
view.mCurrentItem = -1;
view.invalidate();
}
}
private void notifyAdapterDataSetChanged() {
if (getAdapter() == null) {
return;
}
getAdapter().notifyDataSetChanged();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
return mDelegate.isWeekViewScrollable() && super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDelegate.isWeekViewScrollable() && super.onInterceptTouchEvent(ev);
}
/**
* 周视图的高度应该与日历项的高度一致
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mDelegate.getCalendarItemHeight(), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 周视图切换
*/
private class WeekViewPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return mWeekCount;
}
@Override
public int getItemPosition(@NonNull Object object) {
return isUpdateWeekView ? POSITION_NONE : super.getItemPosition(object);
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view.equals(object);
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Calendar calendar = CalendarUtil.getFirstCalendarStartWithMinCalendar(mDelegate.getMinYear(),
mDelegate.getMinYearMonth(),
mDelegate.getMinYearDay(),
position + 1,
mDelegate.getWeekStart());
BaseWeekView view;
try {
Constructor constructor = mDelegate.getWeekViewClass().getConstructor(Context.class);
view = (BaseWeekView) constructor.newInstance(getContext());
} catch (Exception e) {
e.printStackTrace();
return new DefaultWeekView(getContext());
}
view.mParentLayout = mParentLayout;
view.setup(mDelegate);
view.setup(calendar);
view.setTag(position);
view.setSelectedCalendar(mDelegate.mSelectedCalendar);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
BaseWeekView view = (BaseWeekView) object;
view.onDestroy();
container.removeView(view);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
/**
* 年份布局选择View
*/
public final class YearRecyclerView extends RecyclerView {
private CalendarViewDelegate mDelegate;
private YearViewAdapter mAdapter;
private OnMonthSelectedListener mListener;
public YearRecyclerView(Context context) {
this(context, null);
}
public YearRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mAdapter = new YearViewAdapter(context);
setLayoutManager(new GridLayoutManager(context, 3));
setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position, long itemId) {
if (mListener != null && mDelegate != null) {
Month month = mAdapter.getItem(position);
if (month == null) {
return;
}
if (!CalendarUtil.isMonthInRange(month.getYear(), month.getMonth(),
mDelegate.getMinYear(), mDelegate.getMinYearMonth(),
mDelegate.getMaxYear(), mDelegate.getMaxYearMonth())) {
return;
}
mListener.onMonthSelected(month.getYear(), month.getMonth());
if (mDelegate.mYearViewChangeListener != null) {
mDelegate.mYearViewChangeListener.onYearViewChange(true);
}
}
}
});
}
/**
* 设置
*
* @param delegate delegate
*/
final void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
this.mAdapter.setup(delegate);
}
/**
* 初始化年视图
*
* @param year year
*/
final void init(int year) {
java.util.Calendar date = java.util.Calendar.getInstance();
for (int i = 1; i <= 12; i++) {
date.set(year, i - 1, 1);
int mDaysCount = CalendarUtil.getMonthDaysCount(year, i);
Month month = new Month();
month.setDiff(CalendarUtil.getMonthViewStartDiff(year, i, mDelegate.getWeekStart()));
month.setCount(mDaysCount);
month.setMonth(i);
month.setYear(year);
mAdapter.addItem(month);
}
}
/**
* 更新周起始
*/
final void updateWeekStart() {
for (Month month : mAdapter.getItems()) {
month.setDiff(CalendarUtil.getMonthViewStartDiff(month.getYear(), month.getMonth(), mDelegate.getWeekStart()));
}
}
/**
* 更新字体颜色大小
*/
final void updateStyle(){
for (int i = 0; i < getChildCount(); i++) {
YearView view = (YearView) getChildAt(i);
view.updateStyle();
view.invalidate();
}
}
/**
* 月份选择事件
*
* @param listener listener
*/
final void setOnMonthSelectedListener(OnMonthSelectedListener listener) {
this.mListener = listener;
}
void notifyAdapterDataSetChanged(){
if(getAdapter() == null){
return;
}
getAdapter().notifyDataSetChanged();
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int height = MeasureSpec.getSize(heightSpec);
int width = MeasureSpec.getSize(widthSpec);
mAdapter.setYearViewSize(width / 3, height / 4);
}
interface OnMonthSelectedListener {
void onMonthSelected(int year, int month);
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import java.util.List;
/**
* 年视图
*/
@SuppressWarnings("unused")
public abstract class YearView extends View {
CalendarViewDelegate mDelegate;
/**
* 当前月份日期的笔
*/
protected Paint mCurMonthTextPaint = new Paint();
/**
* 其它月份日期颜色
*/
protected Paint mOtherMonthTextPaint = new Paint();
/**
* 当前月份农历文本颜色
*/
protected Paint mCurMonthLunarTextPaint = new Paint();
/**
* 当前月份农历文本颜色
*/
protected Paint mSelectedLunarTextPaint = new Paint();
/**
* 其它月份农历文本颜色
*/
protected Paint mOtherMonthLunarTextPaint = new Paint();
/**
* 其它月份农历文本颜色
*/
protected Paint mSchemeLunarTextPaint = new Paint();
/**
* 标记的日期背景颜色画笔
*/
protected Paint mSchemePaint = new Paint();
/**
* 被选择的日期背景色
*/
protected Paint mSelectedPaint = new Paint();
/**
* 标记的文本画笔
*/
protected Paint mSchemeTextPaint = new Paint();
/**
* 选中的文本画笔
*/
protected Paint mSelectTextPaint = new Paint();
/**
* 当前日期文本颜色画笔
*/
protected Paint mCurDayTextPaint = new Paint();
/**
* 当前日期文本颜色画笔
*/
protected Paint mCurDayLunarTextPaint = new Paint();
/**
* 月份画笔
*/
protected Paint mMonthTextPaint = new Paint();
/**
* 周栏画笔
*/
protected Paint mWeekTextPaint = new Paint();
/**
* 日历项
*/
List<Calendar> mItems;
/**
* 每一项的高度
*/
protected int mItemHeight;
/**
* 每一项的宽度
*/
protected int mItemWidth;
/**
* Text的基线
*/
protected float mTextBaseLine;
/**
* Text的基线
*/
protected float mMonthTextBaseLine;
/**
* Text的基线
*/
protected float mWeekTextBaseLine;
/**
* 当前日历卡年份
*/
protected int mYear;
/**
* 当前日历卡月份
*/
protected int mMonth;
/**
* 下个月偏移的数量
*/
protected int mNextDiff;
/**
* 周起始
*/
protected int mWeekStart;
/**
* 日历的行数
*/
protected int mLineCount;
public YearView(Context context) {
this(context, null);
}
public YearView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint();
}
/**
* 初始化配置
*/
private void initPaint() {
mCurMonthTextPaint.setAntiAlias(true);
mCurMonthTextPaint.setTextAlign(Paint.Align.CENTER);
mCurMonthTextPaint.setColor(0xFF111111);
mCurMonthTextPaint.setFakeBoldText(true);
mOtherMonthTextPaint.setAntiAlias(true);
mOtherMonthTextPaint.setTextAlign(Paint.Align.CENTER);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthTextPaint.setFakeBoldText(true);
mCurMonthLunarTextPaint.setAntiAlias(true);
mCurMonthLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mSelectedLunarTextPaint.setAntiAlias(true);
mSelectedLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mOtherMonthLunarTextPaint.setAntiAlias(true);
mOtherMonthLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mMonthTextPaint.setAntiAlias(true);
mMonthTextPaint.setFakeBoldText(true);
mWeekTextPaint.setAntiAlias(true);
mWeekTextPaint.setFakeBoldText(true);
mWeekTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeLunarTextPaint.setAntiAlias(true);
mSchemeLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeTextPaint.setAntiAlias(true);
mSchemeTextPaint.setStyle(Paint.Style.FILL);
mSchemeTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeTextPaint.setColor(0xffed5353);
mSchemeTextPaint.setFakeBoldText(true);
mSelectTextPaint.setAntiAlias(true);
mSelectTextPaint.setStyle(Paint.Style.FILL);
mSelectTextPaint.setTextAlign(Paint.Align.CENTER);
mSelectTextPaint.setColor(0xffed5353);
mSelectTextPaint.setFakeBoldText(true);
mSchemePaint.setAntiAlias(true);
mSchemePaint.setStyle(Paint.Style.FILL);
mSchemePaint.setStrokeWidth(2);
mSchemePaint.setColor(0xffefefef);
mCurDayTextPaint.setAntiAlias(true);
mCurDayTextPaint.setTextAlign(Paint.Align.CENTER);
mCurDayTextPaint.setColor(Color.RED);
mCurDayTextPaint.setFakeBoldText(true);
mCurDayLunarTextPaint.setAntiAlias(true);
mCurDayLunarTextPaint.setTextAlign(Paint.Align.CENTER);
mCurDayLunarTextPaint.setColor(Color.RED);
mCurDayLunarTextPaint.setFakeBoldText(true);
mSelectedPaint.setAntiAlias(true);
mSelectedPaint.setStyle(Paint.Style.FILL);
mSelectedPaint.setStrokeWidth(2);
}
/**
* 设置
*
* @param delegate delegate
*/
final void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
updateStyle();
}
final void updateStyle(){
if(mDelegate == null){
return;
}
this.mCurMonthTextPaint.setTextSize(mDelegate.getYearViewDayTextSize());
this.mSchemeTextPaint.setTextSize(mDelegate.getYearViewDayTextSize());
this.mOtherMonthTextPaint.setTextSize(mDelegate.getYearViewDayTextSize());
this.mCurDayTextPaint.setTextSize(mDelegate.getYearViewDayTextSize());
this.mSelectTextPaint.setTextSize(mDelegate.getYearViewDayTextSize());
this.mSchemeTextPaint.setColor(mDelegate.getYearViewSchemeTextColor());
this.mCurMonthTextPaint.setColor(mDelegate.getYearViewDayTextColor());
this.mOtherMonthTextPaint.setColor(mDelegate.getYearViewDayTextColor());
this.mCurDayTextPaint.setColor(mDelegate.getYearViewCurDayTextColor());
this.mSelectTextPaint.setColor(mDelegate.getYearViewSelectTextColor());
this.mMonthTextPaint.setTextSize(mDelegate.getYearViewMonthTextSize());
this.mMonthTextPaint.setColor(mDelegate.getYearViewMonthTextColor());
this.mWeekTextPaint.setColor(mDelegate.getYearViewWeekTextColor());
this.mWeekTextPaint.setTextSize(mDelegate.getYearViewWeekTextSize());
}
/**
* 初始化年视图
*
* @param year year
* @param month month
*/
final void init(int year, int month) {
mYear = year;
mMonth = month;
mNextDiff = CalendarUtil.getMonthEndDiff(mYear, mMonth, mDelegate.getWeekStart());
int preDiff = CalendarUtil.getMonthViewStartDiff(mYear, mMonth, mDelegate.getWeekStart());
mItems = CalendarUtil.initCalendarForMonthView(mYear, mMonth, mDelegate.getCurrentDay(), mDelegate.getWeekStart());
mLineCount = 6;
addSchemesFromMap();
}
/**
* 测量大小
*
* @param width width
* @param height height
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
final void measureSize(int width, int height) {
Rect rect = new Rect();
mCurMonthTextPaint.getTextBounds("1", 0, 1, rect);
int textHeight = rect.height();
int mMinHeight = 12 * textHeight + getMonthViewTop();
int h = height >= mMinHeight ? height : mMinHeight;
getLayoutParams().width = width;
getLayoutParams().height = h;
mItemHeight = (h - getMonthViewTop()) / 6;
Paint.FontMetrics metrics = mCurMonthTextPaint.getFontMetrics();
mTextBaseLine = mItemHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
Paint.FontMetrics monthMetrics = mMonthTextPaint.getFontMetrics();
mMonthTextBaseLine = mDelegate.getYearViewMonthHeight() / 2 - monthMetrics.descent +
(monthMetrics.bottom - monthMetrics.top) / 2;
Paint.FontMetrics weekMetrics = mWeekTextPaint.getFontMetrics();
mWeekTextBaseLine = mDelegate.getYearViewWeekHeight() / 2 - weekMetrics.descent +
(weekMetrics.bottom - weekMetrics.top) / 2;
invalidate();
}
/**
* 添加事件标记,来自Map
*/
private void addSchemesFromMap() {
if (mDelegate.mSchemeDatesMap == null || mDelegate.mSchemeDatesMap.size() == 0) {
return;
}
for (Calendar a : mItems) {
if (mDelegate.mSchemeDatesMap.containsKey(a.toString())) {
Calendar d = mDelegate.mSchemeDatesMap.get(a.toString());
if(d == null){
continue;
}
a.setScheme(TextUtils.isEmpty(d.getScheme()) ? mDelegate.getSchemeText() : d.getScheme());
a.setSchemeColor(d.getSchemeColor());
a.setSchemes(d.getSchemes());
} else {
a.setScheme("");
a.setSchemeColor(0);
a.setSchemes(null);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
mItemWidth = (getWidth() -
mDelegate.getYearViewMonthPaddingLeft() -
mDelegate.getYearViewMonthPaddingRight()) / 7;
onPreviewHook();
onDrawMonth(canvas);
onDrawWeek(canvas);
onDrawMonthView(canvas);
}
/**
* 绘制
*
* @param canvas canvas
*/
private void onDrawMonth(Canvas canvas) {
onDrawMonth(canvas,
mYear, mMonth,
mDelegate.getYearViewMonthPaddingLeft(),
mDelegate.getYearViewMonthPaddingTop(),
getWidth() - 2 * mDelegate.getYearViewMonthPaddingRight(),
mDelegate.getYearViewMonthHeight() +
mDelegate.getYearViewMonthPaddingTop());
}
private int getMonthViewTop() {
return mDelegate.getYearViewMonthPaddingTop() +
mDelegate.getYearViewMonthHeight() +
mDelegate.getYearViewMonthPaddingBottom() +
mDelegate.getYearViewWeekHeight();
}
/**
* 绘制
*
* @param canvas canvas
*/
private void onDrawWeek(Canvas canvas) {
if (mDelegate.getYearViewWeekHeight() <= 0) {
return;
}
int week = mDelegate.getWeekStart();
if (week > 0) {
week -= 1;
}
int width = (getWidth() -
mDelegate.getYearViewMonthPaddingLeft() -
mDelegate.getYearViewMonthPaddingRight()) / 7;
for (int i = 0; i < 7; i++) {
onDrawWeek(canvas,
week,
mDelegate.getYearViewMonthPaddingLeft() + i * width,
mDelegate.getYearViewMonthHeight() +
mDelegate.getYearViewMonthPaddingTop() +
mDelegate.getYearViewMonthPaddingBottom(),
width,
mDelegate.getYearViewWeekHeight());
week += 1;
if (week >= 7) {
week = 0;
}
}
}
/**
* 绘制月份数据
*
* @param canvas canvas
*/
private void onDrawMonthView(Canvas canvas) {
int count = mLineCount * 7;
int d = 0;
for (int i = 0; i < mLineCount; i++) {
for (int j = 0; j < 7; j++) {
Calendar calendar = mItems.get(d);
if (d > mItems.size() - mNextDiff) {
return;
}
if (!calendar.isCurrentMonth()) {
++d;
continue;
}
draw(canvas, calendar, i, j, d);
++d;
}
}
}
/**
* 开始绘制
*
* @param canvas canvas
* @param calendar 对应日历
* @param i i
* @param j j
* @param d d
*/
private void draw(Canvas canvas, Calendar calendar, int i, int j, int d) {
int x = j * mItemWidth + mDelegate.getYearViewMonthPaddingLeft();
int y = i * mItemHeight + getMonthViewTop();
boolean isSelected = calendar.equals(mDelegate.mSelectedCalendar);
boolean hasScheme = calendar.hasScheme();
if (hasScheme) {
//标记的日子
boolean isDrawSelected = false;//是否继续绘制选中的onDrawScheme
if (isSelected) {
isDrawSelected = onDrawSelected(canvas, calendar, x, y, true);
}
if (isDrawSelected || !isSelected) {
//将画笔设置为标记颜色
mSchemePaint.setColor(calendar.getSchemeColor() != 0 ? calendar.getSchemeColor() : mDelegate.getSchemeThemeColor());
onDrawScheme(canvas, calendar, x, y);
}
} else {
if (isSelected) {
onDrawSelected(canvas, calendar, x, y, false);
}
}
onDrawText(canvas, calendar, x, y, hasScheme, isSelected);
}
/**
* 开始绘制前的钩子,这里做一些初始化的操作,每次绘制只调用一次,性能高效
* 没有需要可忽略不实现
* 例如:
* 1、需要绘制圆形标记事件背景,可以在这里计算半径
* 2、绘制矩形选中效果,也可以在这里计算矩形宽和高
*/
protected void onPreviewHook() {
// TODO: 2017/11/16
}
/**
* 绘制月份
*
* @param canvas canvas
* @param year year
* @param month month
* @param x x
* @param y y
* @param width width
* @param height height
*/
protected abstract void onDrawMonth(Canvas canvas, int year, int month, int x, int y, int width, int height);
/**
* 绘制年视图的周栏
*
* @param canvas canvas
* @param week week
* @param x x
* @param y y
* @param width width
* @param height height
*/
protected abstract void onDrawWeek(Canvas canvas, int week, int x, int y, int width, int height);
/**
* 绘制选中的日期
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return 是否绘制onDrawScheme,true or false
*/
protected abstract boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme);
/**
* 绘制标记的日期,这里可以是背景色,标记色什么的
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
protected abstract void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y);
/**
* 绘制日历文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
protected abstract void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected);
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import java.lang.reflect.Constructor;
final class YearViewAdapter extends BaseRecyclerAdapter<Month> {
private CalendarViewDelegate mDelegate;
private int mItemWidth, mItemHeight;
YearViewAdapter(Context context) {
super(context);
}
final void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
}
final void setYearViewSize(int width, int height) {
this.mItemWidth = width;
this.mItemHeight = height;
}
@Override
RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) {
YearView yearView;
if (TextUtils.isEmpty(mDelegate.getYearViewClassPath())) {
yearView = new DefaultYearView(mContext);
} else {
try {
Constructor constructor = mDelegate.getYearViewClass().getConstructor(Context.class);
yearView = (YearView) constructor.newInstance(mContext);
} catch (Exception e) {
e.printStackTrace();
yearView = new DefaultYearView(mContext);
}
}
RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,
RecyclerView.LayoutParams.MATCH_PARENT);
yearView.setLayoutParams(params);
return new YearViewHolder(yearView, mDelegate);
}
@Override
void onBindViewHolder(RecyclerView.ViewHolder holder, Month item, int position) {
YearViewHolder h = (YearViewHolder) holder;
YearView view = h.mYearView;
view.init(item.getYear(), item.getMonth());
view.measureSize(mItemWidth, mItemHeight);
}
private static class YearViewHolder extends RecyclerView.ViewHolder {
YearView mYearView;
YearViewHolder(View itemView, CalendarViewDelegate delegate) {
super(itemView);
mYearView = (YearView) itemView;
mYearView.setup(delegate);
}
}
}
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sobot.widget.ui.calenderview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
/**
* 年份+月份选择布局
* ViewPager + RecyclerView
*/
public final class YearViewPager extends ViewPager {
private int mYearCount;
private boolean isUpdateYearView;
private CalendarViewDelegate mDelegate;
private YearRecyclerView.OnMonthSelectedListener mListener;
public YearViewPager(Context context) {
this(context, null);
}
public YearViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
void setup(CalendarViewDelegate delegate) {
this.mDelegate = delegate;
this.mYearCount = mDelegate.getMaxYear() - mDelegate.getMinYear() + 1;
setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return mYearCount;
}
@Override
public int getItemPosition(@NonNull Object object) {
return isUpdateYearView ? POSITION_NONE : super.getItemPosition(object);
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
YearRecyclerView view = new YearRecyclerView(getContext());
container.addView(view);
view.setup(mDelegate);
view.setOnMonthSelectedListener(mListener);
view.init(position + mDelegate.getMinYear());
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
});
setCurrentItem(mDelegate.getCurrentDay().getYear() - mDelegate.getMinYear());
}
@Override
public void setCurrentItem(int item) {
setCurrentItem(item, false);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
if (Math.abs(getCurrentItem() - item) > 1) {
super.setCurrentItem(item, false);
} else {
super.setCurrentItem(item, false);
}
}
/**
* 通知刷新
*/
void notifyDataSetChanged() {
this.mYearCount = mDelegate.getMaxYear() - mDelegate.getMinYear() + 1;
if(getAdapter() != null){
getAdapter().notifyDataSetChanged();
}
}
/**
* 滚动到某年
*
* @param year year
* @param smoothScroll smoothScroll
*/
void scrollToYear(int year, boolean smoothScroll) {
setCurrentItem(year - mDelegate.getMinYear(), smoothScroll);
}
/**
* 更新日期范围
*/
final void updateRange() {
isUpdateYearView = true;
notifyDataSetChanged();
isUpdateYearView = false;
}
/**
* 更新界面
*/
final void update() {
for (int i = 0; i < getChildCount(); i++) {
YearRecyclerView view = (YearRecyclerView) getChildAt(i);
view.notifyAdapterDataSetChanged();
}
}
/**
* 更新周起始
*/
final void updateWeekStart() {
for (int i = 0; i < getChildCount(); i++) {
YearRecyclerView view = (YearRecyclerView) getChildAt(i);
view.updateWeekStart();
view.notifyAdapterDataSetChanged();
}
}
/**
* 更新字体颜色大小
*/
final void updateStyle(){
for (int i = 0; i < getChildCount(); i++) {
YearRecyclerView view = (YearRecyclerView) getChildAt(i);
view.updateStyle();
}
}
final void setOnMonthSelectedListener(YearRecyclerView.OnMonthSelectedListener listener) {
this.mListener = listener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//heightMeasureSpec = MeasureSpec.makeMeasureSpec(getHeight(getContext(), this), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 计算相对高度
*
* @param context context
* @param view view
* @return 年月视图选择器最适合的高度
*/
private static int getHeight(Context context, View view) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
assert manager != null;
Display display = manager.getDefaultDisplay();
int h = display.getHeight();
int[] location = new int[2];
view.getLocationInWindow(location);
view.getLocationOnScreen(location);
return h - location[1];
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
return mDelegate.isYearViewScrollable() && super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDelegate.isYearViewScrollable() && super.onInterceptTouchEvent(ev);
}
}
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll_week"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#FFFFFF"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingTop="8dp"
tools:ignore="HardcodedText">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sun"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/mon"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/tue"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/wed"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/thu"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/fri"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sat"
android:textColor="@color/sobot_common_gray1"
android:textSize="12sp" />
</merge>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="HardcodedText">
<FrameLayout
android:id="@+id/frameContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible">
<com.sobot.widget.ui.calenderview.MonthViewPager
android:id="@+id/vp_month"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="41dp" />
<com.sobot.widget.ui.calenderview.WeekViewPager
android:id="@+id/vp_week"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="41dp"
android:visibility="gone" />
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="40dp"
android:background="#cfcfcf" />
</FrameLayout>
<com.sobot.widget.ui.calenderview.YearViewPager
android:id="@+id/selectLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:visibility="gone" />
</merge>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll_week"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#FFFFFF"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingTop="8dp"
tools:ignore="HardcodedText">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sun"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/mon"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/tue"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/wed"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/thu"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/fri"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sat"
android:textColor="#333333"
android:textSize="12sp" />
</merge>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string-array name="lunar_first_of_month">
<item>春节</item>
<item>二月</item>
<item>三月</item>
<item>四月</item>
<item>五月</item>
<item>六月</item>
<item>七月</item>
<item>八月</item>
<item>九月</item>
<item>十月</item>
<item>冬月</item>
<item>腊月</item>
</string-array>
<string-array name="tradition_festival">
<item>除夕</item>
<item>0101春节</item>
<item>0115元宵</item>
<item>0505端午</item>
<item>0707七夕</item>
<item>0815中秋</item>
<item>0909重阳</item>
</string-array>
<string-array name="lunar_str">
<item>初一</item>
<item>初二</item>
<item>初三</item>
<item>初四</item>
<item>初五</item>
<item>初六</item>
<item>初七</item>
<item>初八</item>
<item>初九</item>
<item>初十</item>
<item>十一</item>
<item>十二</item>
<item>十三</item>
<item>十四</item>
<item>十五</item>
<item>十六</item>
<item>十七</item>
<item>十八</item>
<item>十九</item>
<item>二十</item>
<item>廿一</item>
<item>廿二</item>
<item>廿三</item>
<item>廿四</item>
<item>廿五</item>
<item>廿六</item>
<item>廿七</item>
<item>廿八</item>
<item>廿九</item>
<item>三十</item>
</string-array>
<string-array name="solar_festival" tools:ignore="InconsistentArrays">
<item>0101元旦</item>
<item>0214情人节</item>
<item>0308妇女节</item>
<item>0312植树节</item>
<item>0315消权日</item>
<item>0401愚人节</item>
<item>0422地球日</item>
<item>0501劳动节</item>
<item>0504青年节</item>
<item>0601儿童节</item>
<item>0701建党节</item>
<item>0801建军节</item>
<item>0910教师节</item>
<item>1001国庆节</item>
<item>1031万圣节</item>
<item>1111光棍节</item>
<item>1224平安夜</item>
<item>1225圣诞节</item>
</string-array>
<string-array name="solar_term">
<item>春分</item>
<item>清明</item>
<item>谷雨</item>
<item>立夏</item>
<item>小满</item>
<item>芒种</item>
<item>夏至</item>
<item>小暑</item>
<item>大暑</item>
<item>立秋</item>
<item>处暑</item>
<item>白露</item>
<item>秋分</item>
<item>寒露</item>
<item>霜降</item>
<item>立冬</item>
<item>小雪</item>
<item>大雪</item>
<item>冬至</item>
<item>小寒</item>
<item>大寒</item>
<item>立春</item>
<item>雨水</item>
<item>惊蛰</item>
</string-array>
<string-array name="special_festivals">
<item>母亲节</item>
<item>父亲节</item>
<item>感恩节</item>
</string-array>
<string name="sun">Sun</string>
<string name="mon">Mon</string>
<string name="tue">Tue</string>
<string name="wed">Wed</string>
<string name="thu">Thu</string>
<string name="fri">Fri</string>
<string name="sat">Sat</string>
<string-array name="week_string_array">
<item>Sun</item>
<item>Mon</item>
<item>Tue</item>
<item>Wed</item>
<item>Thu</item>
<item>Fri</item>
<item>Sat</item>
</string-array>
<string-array name="year_view_week_string_array">
<item>S</item>
<item>M</item>
<item>T</item>
<item>W</item>
<item>T</item>
<item>F</item>
<item>S</item>
</string-array>
<string-array name="month_string_array">
<item>JAN</item>
<item>FEB</item>
<item>MAR</item>
<item>APR</item>
<item>MAY</item>
<item>JUN</item>
<item>JUL</item>
<item>AUG</item>
<item>SEP</item>
<item>OCT</item>
<item>NOV</item>
<item>DEC</item>
</string-array>
<integer-array name="trunk_integer_array">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
</integer-array>
<string-array name="trunk_string_array">
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<integer-array name="branch_integer_array">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
</integer-array>
<string-array name="branch_string_array">
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
\ No newline at end of file
...@@ -245,4 +245,145 @@ ...@@ -245,4 +245,145 @@
<attr name="sobot_stroke_width" /> <attr name="sobot_stroke_width" />
<attr name="sobot_clip_background" /> <attr name="sobot_clip_background" />
</declare-styleable> </declare-styleable>
<declare-styleable name="Sobot_CalendarView">
<attr name="calendar_padding" format="dimension" /><!--日历内部左右padding-->
<attr name="calendar_padding_left" format="dimension" /><!--日历内部左padding-->
<attr name="calendar_padding_right" format="dimension" /><!--日历内部右padding-->
<attr name="week_background" format="color" /><!--周背景-->
<attr name="week_line_background" format="color" /><!--线条颜色-->
<attr name="week_text_color" format="color" /><!--周栏字体颜色-->
<attr name="week_text_size" format="dimension" /><!--周栏字体大小-->
<attr name="week_line_margin" format="dimension" /><!--线条margin-->
<attr name="month_view" format="string" /><!--完全自定义月视图-->
<attr name="week_view" format="string" /> <!--完全自定义周视图-->
<attr name="year_view" format="string" /> <!--完全自定义年视图-->
<attr name="week_bar_height" format="dimension" /> <!--星期栏的高度-->
<attr name="week_bar_view" format="string" /> <!--如果需要的话使用自定义星期栏-->
<attr name="scheme_text" format="string" />
<attr name="day_text_size" format="dimension" />
<attr name="lunar_text_size" format="dimension" />
<attr name="calendar_height" format="dimension" />
<attr name="calendar_match_parent" format="boolean" /> <!-- 全屏日历 -->
<attr name="scheme_text_color" format="color" />
<attr name="scheme_month_text_color" format="color" />
<attr name="scheme_lunar_text_color" format="color" />
<attr name="scheme_theme_color" format="color" />
<attr name="selected_theme_color" format="color" />
<attr name="selected_text_color" format="color" />
<attr name="selected_lunar_text_color" format="color" />
<attr name="current_day_text_color" format="color" />
<attr name="current_day_lunar_text_color" format="color" />
<attr name="current_month_text_color" format="color" />
<attr name="other_month_text_color" format="color" />
<attr name="current_month_lunar_text_color" format="color" />
<attr name="other_month_lunar_text_color" format="color" />
<!-- 年视图相关 -->
<attr name="year_view_month_text_size" format="dimension" />
<attr name="year_view_day_text_size" format="dimension" />
<attr name="year_view_month_text_color" format="color" />
<attr name="year_view_current_day_text_color" format="color" />
<attr name="year_view_day_text_color" format="color" />
<attr name="year_view_select_text_color" format="color" />
<attr name="year_view_scheme_color" format="color" />
<attr name="year_view_background" format="color" />
<attr name="year_view_month_height" format="dimension" />
<attr name="year_view_week_height" format="dimension" />
<attr name="year_view_week_text_size" format="dimension" />
<attr name="year_view_week_text_color" format="color" />
<attr name="year_view_padding" format="dimension" />
<attr name="year_view_padding_left" format="dimension" />
<attr name="year_view_padding_right" format="dimension" />
<attr name="year_view_month_padding_top" format="dimension" />
<attr name="year_view_month_padding_left" format="dimension" />
<attr name="year_view_month_padding_right" format="dimension" />
<attr name="year_view_month_padding_bottom" format="dimension" />
<!--日期范围-->
<attr name="min_year" format="integer" />
<attr name="max_year" format="integer" />
<attr name="min_year_month" format="integer" />
<attr name="max_year_month" format="integer" />
<attr name="min_year_day" format="integer" />
<attr name="max_year_day" format="integer" />
<!--月视图是否可滚动-->
<attr name="month_view_scrollable" format="boolean" />
<!--周视图是否可滚动-->
<attr name="week_view_scrollable" format="boolean" />
<!--年视图是否可滚动-->
<attr name="year_view_scrollable" format="boolean" />
<!-- 月份显示模式 -->
<attr name="month_view_show_mode">
<enum name="mode_all" value="0" />
<enum name="mode_only_current" value="1" />
<enum name="mode_fix" value="2" />
</attr>
<!-- 自定义周起始 -->
<attr name="week_start_with">
<enum name="sun" value="1" />
<enum name="mon" value="2" />
<enum name="sat" value="7" />
</attr>
<!-- 自定义选择模式 -->
<attr name="select_mode">
<enum name="default_mode" value="0" />
<enum name="single_mode" value="1" />
<enum name="range_mode" value="2" />
<enum name="multi_mode" value="3" />
</attr>
<!-- when select_mode = multi_mode -->
<attr name="max_multi_select_size" format="integer" />
<!-- when select_mode = range_mode -->
<attr name="min_select_range" format="integer" />
<attr name="max_select_range" format="integer" />
<!-- auto select day -->
<attr name="month_view_auto_select_day">
<enum name="first_day_of_month" value="0" />
<enum name="last_select_day" value="1" />
<enum name="last_select_day_ignore_current" value="2" />
</attr>
</declare-styleable>
<declare-styleable name="Sobot_CalendarLayout">
<attr name="default_status">
<enum name="expand" value="0" />
<enum name="shrink" value="1" />
</attr>
<!-- 手势模式 -->
<attr name="gesture_mode">
<enum name="default_mode" value="0" />
<!--<enum name="only_calendar" value="1" />-->
<enum name="disabled" value="2" />
</attr>
<attr name="calendar_show_mode">
<enum name="both_month_week_view" value="0" />
<enum name="only_week_view" value="1" />
<enum name="only_month_view" value="2" />
</attr>
<attr name="calendar_content_view_id" format="integer" />
</declare-styleable>
</resources> </resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string-array name="lunar_first_of_month">
<item>春节</item>
<item>二月</item>
<item>三月</item>
<item>四月</item>
<item>五月</item>
<item>六月</item>
<item>七月</item>
<item>八月</item>
<item>九月</item>
<item>十月</item>
<item>冬月</item>
<item>腊月</item>
</string-array>
<string-array name="tradition_festival">
<item>除夕</item>
<item>0101春节</item>
<item>0115元宵</item>
<item>0505端午</item>
<item>0707七夕</item>
<item>0815中秋</item>
<item>0909重阳</item>
</string-array>
<string-array name="lunar_str">
<item>初一</item>
<item>初二</item>
<item>初三</item>
<item>初四</item>
<item>初五</item>
<item>初六</item>
<item>初七</item>
<item>初八</item>
<item>初九</item>
<item>初十</item>
<item>十一</item>
<item>十二</item>
<item>十三</item>
<item>十四</item>
<item>十五</item>
<item>十六</item>
<item>十七</item>
<item>十八</item>
<item>十九</item>
<item>二十</item>
<item>廿一</item>
<item>廿二</item>
<item>廿三</item>
<item>廿四</item>
<item>廿五</item>
<item>廿六</item>
<item>廿七</item>
<item>廿八</item>
<item>廿九</item>
<item>三十</item>
</string-array>
<string-array name="solar_festival" tools:ignore="InconsistentArrays">
<item>0101元旦</item>
<item>0214情人节</item>
<item>0308妇女节</item>
<item>0312植树节</item>
<item>0315消权日</item>
<item>0401愚人节</item>
<item>0422地球日</item>
<item>0501劳动节</item>
<item>0504青年节</item>
<item>0601儿童节</item>
<item>0701建党节</item>
<item>0801建军节</item>
<item>0910教师节</item>
<item>1001国庆节</item>
<item>1031万圣节</item>
<item>1111光棍节</item>
<item>1224平安夜</item>
<item>1225圣诞节</item>
</string-array>
<string-array name="solar_term">
<item>春分</item>
<item>清明</item>
<item>谷雨</item>
<item>立夏</item>
<item>小满</item>
<item>芒种</item>
<item>夏至</item>
<item>小暑</item>
<item>大暑</item>
<item>立秋</item>
<item>处暑</item>
<item>白露</item>
<item>秋分</item>
<item>寒露</item>
<item>霜降</item>
<item>立冬</item>
<item>小雪</item>
<item>大雪</item>
<item>冬至</item>
<item>小寒</item>
<item>大寒</item>
<item>立春</item>
<item>雨水</item>
<item>惊蛰</item>
</string-array>
<string-array name="special_festivals">
<item>母亲节</item>
<item>父亲节</item>
<item>感恩节</item>
</string-array>
<string name="sun"></string>
<string name="mon"></string>
<string name="tue"></string>
<string name="wed"></string>
<string name="thu"></string>
<string name="fri"></string>
<string name="sat"></string>
<string-array name="week_string_array">
<item>周日</item>
<item>周一</item>
<item>周二</item>
<item>周三</item>
<item>周四</item>
<item>周五</item>
<item>周六</item>
</string-array>
<string-array name="year_view_week_string_array">
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="month_string_array">
<item>1月</item>
<item>2月</item>
<item>3月</item>
<item>4月</item>
<item>5月</item>
<item>6月</item>
<item>7月</item>
<item>8月</item>
<item>9月</item>
<item>10月</item>
<item>11月</item>
<item>12月</item>
</string-array>
<integer-array name="trunk_integer_array">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
</integer-array>
<string-array name="trunk_string_array">
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<integer-array name="branch_integer_array">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
</integer-array>
<string-array name="branch_string_array">
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment