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;
/**
* 最基础周视图,因为日历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() {
}
}
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;
/**
* 农历计算方法
*/
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.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 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);
}
}
}
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.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.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