Android(安卓)自定义自由选择时间区间的日历控件
16lz
2021-01-26
摸滚打爬在Android界小菜鸟,突然静下心想想自己都做过些什么呢!留下些什么呢!感觉自己老是copy别人的东西自己都不好意思了,于是今天就 来分享下自己最近写项目中的一个自定义日历控件 (翻阅了各大开源日历都没有合适的),希望大家多多指点,第一次写博客如果有不足之处,请尽管喷。
因为自己不知道怎么描述那我就直接上代码了。
因为这个是自己写的demo adapter等没有分开写, 自己分开写Adapter,如果你觉得对你有用可以自己,放在不同的文件夹下面。
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private CalendarListAdapter mAdapter;
private List calendarModels;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
calendarModels = getData();
mListView = (ListView) findViewById(R.id.listview);
mAdapter = new CalendarListAdapter(this);
mListView.setAdapter(mAdapter);
mAdapter.setDataSource(calendarModels);
mAdapter.notifyDataSetChanged();
}
private int lastPosition = 0;
private List getData() {
List calendarModels = new ArrayList();
int year = 2017;
for (int index = 0; index < 12; index++) {
CalendarModel calendarModel = new CalendarModel();
calendarModel.setMonthIndex(index);
calendarModel.setMonthDays(getDaysInMonth(index, year));
if (index == 0) {
calendarModel.setFirstPosition(6);
calendarModel.setLastPosition(1);
lastPosition = 1;
} else {
calendarModel.setFirstPosition(lastPosition + 1);
lastPosition = (getDaysInMonth(index, year) + lastPosition) % 7;
calendarModel.setLastPosition(lastPosition);
}
calendarModels.add(calendarModel);
}
return calendarModels;
}
private int getDaysInMonth(int month, int year) {
switch (month) {
case Calendar.JANUARY:
case Calendar.MARCH:
case Calendar.MAY:
case Calendar.JULY:
case Calendar.AUGUST:
case Calendar.OCTOBER:
case Calendar.DECEMBER:
return 31;
case Calendar.APRIL:
case Calendar.JUNE:
case Calendar.SEPTEMBER:
case Calendar.NOVEMBER:
return 30;
case Calendar.FEBRUARY:
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 29 : 28;
default:
throw new IllegalArgumentException("Invalid Month");
}
}
class CalendarListAdapter extends BaseAdapter {
private Context mContext;
private List dataSource;
public void setDataSource(List dataSource) {
this.dataSource = dataSource;
}
public CalendarListAdapter(Context context) {
mContext = context;
}
@Override
public int getCount() {
return dataSource == null ? 0 : dataSource.size();
}
@Override
public CalendarModel getItem(int i) {
return dataSource == null ? null : dataSource.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item_list_calendar, null);
viewHolder.titleView = (TextView) view.findViewById(R.id.title_tv);
viewHolder.gridView = (CustomGridView) view.findViewById(R.id.days_grid);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
CalendarModel calendarModel = getItem(i);
if (calendarModel != null) {
viewHolder.titleView.setText(String.valueOf(calendarModel.getMonthIndex() + 1));
int first = calendarModel.getFirstPosition();
int last = calendarModel.getLastPosition();
CalendarGridAdapter adapter = new CalendarGridAdapter(mContext,calendarModel.getMonthIndex() + 1);
viewHolder.gridView.setAdapter(adapter);
List dataSource = new ArrayList();
for (int index = 0; index < first; index++) {
DayModel dayModel = new DayModel();
dayModel.setDayIndex(0);
dayModel.setMonthIndex(calendarModel.getMonthIndex() + 1);
dataSource.add(dayModel);
}
int days = calendarModel.getMonthDays();
for (int index = 0; index < days; index++) {
DayModel dayModel = new DayModel();
dayModel.setDayIndex(index + 1);
dataSource.add(dayModel);
}
adapter.setDataSource(dataSource);
adapter.notifyDataSetChanged();
}
return view;
}
class ViewHolder {
TextView titleView;
CustomGridView gridView;
}
}
private List monthDayModels = new ArrayList();
class CalendarGridAdapter extends BaseAdapter {
int curentMonth;
private Context mContext;
private List dataSource;
List> limitTime = new ArrayList>();
public void setDataSource(List dataSource) {
this.dataSource = dataSource;
}
public CalendarGridAdapter(Context context,int curentMonth) {
mContext = context;
this.curentMonth = curentMonth;
//模拟后台指定的开始时间和结束时间
HashMap map1 = new HashMap<>();
map1.put("startTime",1490716800000L);
map1.put("endTime",1491580799000L);
limitTime.add(map1);
HashMap map2 = new HashMap<>();
map2.put("startTime",1491926800000L);
map2.put("endTime",1492444799000L);
limitTime.add(map2);
}
@Override
public int getCount() {
return dataSource == null ? 0 : dataSource.size();
}
@Override
public DayModel getItem(int i) {
return dataSource == null ? null : dataSource.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item_grid_calendar, null);
viewHolder.titleView = (TextView) view.findViewById(R.id.day_tv);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
final View state_line = view.findViewById(R.id.state_line);
final DayModel dayModel = getItem(i);
if (dayModel != null && dayModel.getDayIndex() != 0) {
viewHolder.titleView.setText(String.valueOf(dayModel.getDayIndex()));
viewHolder.titleView.setVisibility(View.VISIBLE);
} else {
viewHolder.titleView.setVisibility(View.INVISIBLE);
}
int month = dayModel.getMonthIndex();
final int day = dayModel.getDayIndex();
int size = monthDayModels.size();
for (int index = 0; index < size; index++) {
MonthDayModel monthDayModel = monthDayModels.get(index);
if (monthDayModel != null) {
if (monthDayModel.getDay() == day && monthDayModel.getMonth() == month) {
viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
} else {
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
}
} else {
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
}
}
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
// Log.e("date",dateStr);
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = simpleDateFormat.parse(dateStr);
final long timeSecond = date.getTime();
boolean isContain = isContaingDate(timeSecond);
if(isContain){
viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
// state_line.setVisibility(View.VISIBLE);
}else{
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
// state_line.setVisibility(View.GONE);
}
if(checkStartTime != 0 && checkEndTime != 0){
//选择了开始时间和结束时间,并且显示区间的下划线
if(timeSecond >= checkStartTime && timeSecond <= checkEndTime){
state_line.setVisibility(View.VISIBLE);
}
}else{
//当天的最后时刻
String todayEnd = "2017-"+curentMonth+"-"+day+" 23:59:59";
//获取当天最后时刻的好描述
long todaySecondEnd = simpleDateFormat.parse(todayEnd).getTime();
//如果选择的开始时间大于当天凌晨0点0分0秒 并且小于当天时间23点59分59秒的时候
//也就是说,只选择了一个开始时间 并且这个开始时间在当天的范围之内 就显示下划线
if(checkStartTime >= timeSecond && checkStartTime <= todaySecondEnd){
state_line.setVisibility(View.VISIBLE);
}else{
state_line.setVisibility(View.GONE);
}
}
viewHolder.titleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isContain = isContaingDate(timeSecond);
if(!isContain){
//在服务器的区间内,才能点击
Toast.makeText(mContext,"所选日期不在要求范围内!",Toast.LENGTH_SHORT).show();
return;
}
if(checkStartTime == 0 && checkEndTime == 0){
//开始时间和结束时间均为空,则先选择开始时间
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
try {
Date date = simpleDateFormat.parse(dateStr);
checkStartTime = date.getTime();
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}else if(checkEndTime == 0 && checkStartTime != 0){
//开始时间不为空,且结束时间为空
String dateStr = "2017-"+curentMonth+"-"+day+" 23:59:59";
try {
Date date = simpleDateFormat.parse(dateStr);
long checkTime = date.getTime();
if(checkTime <= checkStartTime){
Toast.makeText(mContext,"结束时间应该大于开始时间!",Toast.LENGTH_SHORT).show();
return;
}else{
boolean issameSpace = isInSameSpace(checkStartTime,checkTime);
if(issameSpace){
checkEndTime = checkTime;
}else{
Toast.makeText(mContext,"开始时间和结束时间不在同一个可选区间内!",Toast.LENGTH_SHORT).show();
return;
}
}
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}else{
//当开始时间不为空且结束时间也不为空,这个时候,就设置开始时间为当前时间,结束时间为0
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
try {
Date date = simpleDateFormat.parse(dateStr);
checkStartTime = date.getTime();
checkEndTime = 0;
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
} catch (ParseException e) {
e.printStackTrace();
}
return view;
}
/**
* 所选的开始时间和结束时间是否在同一个区间内
* @param startTime
* @param endTime
* @return
*/
boolean isInSameSpace(long startTime,long endTime){
for(HashMap map:limitTime){
long timeStart = map.get("startTime");
long timeEnd = map.get("endTime");
if(startTime >= timeStart && startTime <= timeEnd
&& endTime >= timeStart && endTime <= timeEnd){
return true;
}
}
return false;
}
long checkStartTime = 0,checkEndTime = 0;
private boolean isContaingDate(long timeSecond) {
for(HashMap map:limitTime){
long timeStart = map.get("startTime");
long timeEnd = map.get("endTime");
if(timeSecond >= timeStart && timeSecond <= timeEnd){
return true;
}
}
return false;
}
class ViewHolder {
TextView titleView;
}
}
}
因为自己不知道怎么描述那我就直接上代码了。
因为这个是自己写的demo adapter等没有分开写, 自己分开写Adapter,如果你觉得对你有用可以自己,放在不同的文件夹下面。
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private CalendarListAdapter mAdapter;
private List
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
calendarModels = getData();
mListView = (ListView) findViewById(R.id.listview);
mAdapter = new CalendarListAdapter(this);
mListView.setAdapter(mAdapter);
mAdapter.setDataSource(calendarModels);
mAdapter.notifyDataSetChanged();
}
private int lastPosition = 0;
private List
List
int year = 2017;
for (int index = 0; index < 12; index++) {
CalendarModel calendarModel = new CalendarModel();
calendarModel.setMonthIndex(index);
calendarModel.setMonthDays(getDaysInMonth(index, year));
if (index == 0) {
calendarModel.setFirstPosition(6);
calendarModel.setLastPosition(1);
lastPosition = 1;
} else {
calendarModel.setFirstPosition(lastPosition + 1);
lastPosition = (getDaysInMonth(index, year) + lastPosition) % 7;
calendarModel.setLastPosition(lastPosition);
}
calendarModels.add(calendarModel);
}
return calendarModels;
}
private int getDaysInMonth(int month, int year) {
switch (month) {
case Calendar.JANUARY:
case Calendar.MARCH:
case Calendar.MAY:
case Calendar.JULY:
case Calendar.AUGUST:
case Calendar.OCTOBER:
case Calendar.DECEMBER:
return 31;
case Calendar.APRIL:
case Calendar.JUNE:
case Calendar.SEPTEMBER:
case Calendar.NOVEMBER:
return 30;
case Calendar.FEBRUARY:
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 29 : 28;
default:
throw new IllegalArgumentException("Invalid Month");
}
}
class CalendarListAdapter extends BaseAdapter {
private Context mContext;
private List
public void setDataSource(List
this.dataSource = dataSource;
}
public CalendarListAdapter(Context context) {
mContext = context;
}
@Override
public int getCount() {
return dataSource == null ? 0 : dataSource.size();
}
@Override
public CalendarModel getItem(int i) {
return dataSource == null ? null : dataSource.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item_list_calendar, null);
viewHolder.titleView = (TextView) view.findViewById(R.id.title_tv);
viewHolder.gridView = (CustomGridView) view.findViewById(R.id.days_grid);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
CalendarModel calendarModel = getItem(i);
if (calendarModel != null) {
viewHolder.titleView.setText(String.valueOf(calendarModel.getMonthIndex() + 1));
int first = calendarModel.getFirstPosition();
int last = calendarModel.getLastPosition();
CalendarGridAdapter adapter = new CalendarGridAdapter(mContext,calendarModel.getMonthIndex() + 1);
viewHolder.gridView.setAdapter(adapter);
List
for (int index = 0; index < first; index++) {
DayModel dayModel = new DayModel();
dayModel.setDayIndex(0);
dayModel.setMonthIndex(calendarModel.getMonthIndex() + 1);
dataSource.add(dayModel);
}
int days = calendarModel.getMonthDays();
for (int index = 0; index < days; index++) {
DayModel dayModel = new DayModel();
dayModel.setDayIndex(index + 1);
dataSource.add(dayModel);
}
adapter.setDataSource(dataSource);
adapter.notifyDataSetChanged();
}
return view;
}
class ViewHolder {
TextView titleView;
CustomGridView gridView;
}
}
private List
class CalendarGridAdapter extends BaseAdapter {
int curentMonth;
private Context mContext;
private List
List
public void setDataSource(List
this.dataSource = dataSource;
}
public CalendarGridAdapter(Context context,int curentMonth) {
mContext = context;
this.curentMonth = curentMonth;
//模拟后台指定的开始时间和结束时间
HashMap
map1.put("startTime",1490716800000L);
map1.put("endTime",1491580799000L);
limitTime.add(map1);
HashMap
map2.put("startTime",1491926800000L);
map2.put("endTime",1492444799000L);
limitTime.add(map2);
}
@Override
public int getCount() {
return dataSource == null ? 0 : dataSource.size();
}
@Override
public DayModel getItem(int i) {
return dataSource == null ? null : dataSource.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item_grid_calendar, null);
viewHolder.titleView = (TextView) view.findViewById(R.id.day_tv);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
final View state_line = view.findViewById(R.id.state_line);
final DayModel dayModel = getItem(i);
if (dayModel != null && dayModel.getDayIndex() != 0) {
viewHolder.titleView.setText(String.valueOf(dayModel.getDayIndex()));
viewHolder.titleView.setVisibility(View.VISIBLE);
} else {
viewHolder.titleView.setVisibility(View.INVISIBLE);
}
int month = dayModel.getMonthIndex();
final int day = dayModel.getDayIndex();
int size = monthDayModels.size();
for (int index = 0; index < size; index++) {
MonthDayModel monthDayModel = monthDayModels.get(index);
if (monthDayModel != null) {
if (monthDayModel.getDay() == day && monthDayModel.getMonth() == month) {
viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
} else {
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
}
} else {
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
}
}
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
// Log.e("date",dateStr);
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = simpleDateFormat.parse(dateStr);
final long timeSecond = date.getTime();
boolean isContain = isContaingDate(timeSecond);
if(isContain){
viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
// state_line.setVisibility(View.VISIBLE);
}else{
viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
// state_line.setVisibility(View.GONE);
}
if(checkStartTime != 0 && checkEndTime != 0){
//选择了开始时间和结束时间,并且显示区间的下划线
if(timeSecond >= checkStartTime && timeSecond <= checkEndTime){
state_line.setVisibility(View.VISIBLE);
}
}else{
//当天的最后时刻
String todayEnd = "2017-"+curentMonth+"-"+day+" 23:59:59";
//获取当天最后时刻的好描述
long todaySecondEnd = simpleDateFormat.parse(todayEnd).getTime();
//如果选择的开始时间大于当天凌晨0点0分0秒 并且小于当天时间23点59分59秒的时候
//也就是说,只选择了一个开始时间 并且这个开始时间在当天的范围之内 就显示下划线
if(checkStartTime >= timeSecond && checkStartTime <= todaySecondEnd){
state_line.setVisibility(View.VISIBLE);
}else{
state_line.setVisibility(View.GONE);
}
}
viewHolder.titleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isContain = isContaingDate(timeSecond);
if(!isContain){
//在服务器的区间内,才能点击
Toast.makeText(mContext,"所选日期不在要求范围内!",Toast.LENGTH_SHORT).show();
return;
}
if(checkStartTime == 0 && checkEndTime == 0){
//开始时间和结束时间均为空,则先选择开始时间
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
try {
Date date = simpleDateFormat.parse(dateStr);
checkStartTime = date.getTime();
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}else if(checkEndTime == 0 && checkStartTime != 0){
//开始时间不为空,且结束时间为空
String dateStr = "2017-"+curentMonth+"-"+day+" 23:59:59";
try {
Date date = simpleDateFormat.parse(dateStr);
long checkTime = date.getTime();
if(checkTime <= checkStartTime){
Toast.makeText(mContext,"结束时间应该大于开始时间!",Toast.LENGTH_SHORT).show();
return;
}else{
boolean issameSpace = isInSameSpace(checkStartTime,checkTime);
if(issameSpace){
checkEndTime = checkTime;
}else{
Toast.makeText(mContext,"开始时间和结束时间不在同一个可选区间内!",Toast.LENGTH_SHORT).show();
return;
}
}
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}else{
//当开始时间不为空且结束时间也不为空,这个时候,就设置开始时间为当前时间,结束时间为0
String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
try {
Date date = simpleDateFormat.parse(dateStr);
checkStartTime = date.getTime();
checkEndTime = 0;
notifyDataSetChanged();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
} catch (ParseException e) {
e.printStackTrace();
}
return view;
}
/**
* 所选的开始时间和结束时间是否在同一个区间内
* @param startTime
* @param endTime
* @return
*/
boolean isInSameSpace(long startTime,long endTime){
for(HashMap
long timeStart = map.get("startTime");
long timeEnd = map.get("endTime");
if(startTime >= timeStart && startTime <= timeEnd
&& endTime >= timeStart && endTime <= timeEnd){
return true;
}
}
return false;
}
long checkStartTime = 0,checkEndTime = 0;
private boolean isContaingDate(long timeSecond) {
for(HashMap
long timeStart = map.get("startTime");
long timeEnd = map.get("endTime");
if(timeSecond >= timeStart && timeSecond <= timeEnd){
return true;
}
}
return false;
}
class ViewHolder {
TextView titleView;
}
}
}
后期我会把代码整理好开源给小伙伴们......
Demo地址:http://download.csdn.net/detail/bimromatic/9837950
更多相关文章
- Android(安卓)优化电池使用时间 ——监控电池电量和充电状态
- Android(安卓)进阶——实现周期性任务调度的几种攻略详解
- 修改android 4.4系统下面的休眠时间,只留下永不休眠选项
- android listview adapter中设置点击直接position被重用问题解决
- Android和Linux的时间戳
- 自定义样式日期时间选择对话框控件(精简版)
- 针对Android(安卓)模拟器启动慢的问题,长时间显示 Android(安卓)L
- Android滚轮时间选择控件(可扩展自定义)
- android 可以精确到秒级的时间选择器