Android 自定義自由選擇時間區間的日曆控制元件
阿新 • • 發佈:2019-02-10
摸滾打爬在Android界小菜鳥,突然靜下心想想自己都做過些什麼呢!留下些什麼呢!感覺自己老是copy別人的東西自己都不好意思了,於是今天就 來分享下自己最近寫專案中的一個自定義日曆控制元件 (翻閱了各大開源日曆都沒有合適的),希望大家多多指點,第一次寫部落格如果有不足之處,請儘管噴。
因為自己不知道怎麼描述那我就直接上程式碼了。
因為這個是自己寫的demo adapter等沒有分開寫, 自己分開寫Adapter,如果你覺得對你有用可以自己,放在不同的資料夾下面。
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private CalendarListAdapter mAdapter;
private List<CalendarModel> 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<CalendarModel> getData() {
List<CalendarModel> calendarModels = new ArrayList<CalendarModel>();
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<CalendarModel> dataSource;
public void setDataSource(List<CalendarModel> 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<DayModel> dataSource = new ArrayList<DayModel>();
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<MonthDayModel> monthDayModels = new ArrayList<MonthDayModel>();
class CalendarGridAdapter extends BaseAdapter {
int curentMonth;
private Context mContext;
private List<DayModel> dataSource;
List<HashMap<String,Long>> limitTime = new ArrayList<HashMap<String,Long>>();
public void setDataSource(List<DayModel> dataSource) {
this.dataSource = dataSource;
}
public CalendarGridAdapter(Context context,int curentMonth) {
mContext = context;
this.curentMonth = curentMonth;
//模擬後臺指定的開始時間和結束時間
HashMap<String,Long> map1 = new HashMap<>();
map1.put("startTime",1490716800000L);
map1.put("endTime",1491580799000L);
limitTime.add(map1);
HashMap<String,Long> 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<String,Long> 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<String,Long> 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<CalendarModel> 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<CalendarModel> getData() {
List<CalendarModel> calendarModels = new ArrayList<CalendarModel>();
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<CalendarModel> dataSource;
public void setDataSource(List<CalendarModel> 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<DayModel> dataSource = new ArrayList<DayModel>();
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<MonthDayModel> monthDayModels = new ArrayList<MonthDayModel>();
class CalendarGridAdapter extends BaseAdapter {
int curentMonth;
private Context mContext;
private List<DayModel> dataSource;
List<HashMap<String,Long>> limitTime = new ArrayList<HashMap<String,Long>>();
public void setDataSource(List<DayModel> dataSource) {
this.dataSource = dataSource;
}
public CalendarGridAdapter(Context context,int curentMonth) {
mContext = context;
this.curentMonth = curentMonth;
//模擬後臺指定的開始時間和結束時間
HashMap<String,Long> map1 = new HashMap<>();
map1.put("startTime",1490716800000L);
map1.put("endTime",1491580799000L);
limitTime.add(map1);
HashMap<String,Long> 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<String,Long> 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<String,Long> 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地址:http://download.csdn.net/detail/bimromatic/9837950