赞
踩
一,效果图
1.1 单选
2.2 多选
二 实现思路
2.1 数据来源,利用原生日历Calendar,获取从本月开始的往后一年的日期,遍历月数添加全部天数据
- private void initCalendarData() {
- Calendar calendar = Calendar.getInstance();
- year = calendar.get(Calendar.YEAR);
- month = calendar.get(Calendar.MONTH);
- day = calendar.get(Calendar.DAY_OF_MONTH);
- nowDay = day;
- calendar.set(year, month, 1);
-
- for (int i = 0; i < 12; i++) {
- List<DateEntity> deList = new ArrayList<>();
- MonthEntity monthEntity = new MonthEntity();
- int maxDayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
- int empty = calendar.get(Calendar.DAY_OF_WEEK);
- empty = empty == 1 ? 6 : empty - 2;
- for (int j = 0; j < empty; j++) {
- DateEntity de = new DateEntity();
- de.setType(1);
- deList.add(de);
- }
- for (int j = 1; j <= maxDayOfMonth; j++) {
- DateEntity de = new DateEntity();
- if (i == 0) {
- de.setType(j < nowDay ? 4 : 0);
- } else {
- de.setType(0);
- }
-
- de.setDate(j);
- if (i == 0 && nowDay == j) {
- de.setToday(true);
- } else {
- de.setToday(false);
- }
- de.setParentPos(i);
- String[] result=DatePickerUtils.getLunarDate(year, month + 1, j);
- de.setDesType(result[0]);
- de.setDesc(result[1]);
- deList.add(de);
- }
-
- year = calendar.get(Calendar.YEAR);
- month = calendar.get(Calendar.MONTH) + 1;
- monthEntity.setTitle(year + "年" + month + "月");
- monthEntity.setYear(year);
- monthEntity.setMonth(month);
- monthEntity.setList(deList);
- monthList.add(monthEntity);
-
- calendar.add(Calendar.MONTH, 1);
- }
- }
2.2 添加公立,农历,节气数据。下面只是节假日的判断。
- private static String getChinaCalendarMsg(int year, int month, int day) {
- String message = "";
- if (((month) == 1) && day == 1) {
- message = "春节";
- } else if (((month) == 1) && day == 15) {
- message = "元宵";
- } else if (((month) == 5) && day == 5) {
- message = "端午";
- } else if ((month == 7) && day == 7) {
- message = "七夕";
- } else if (((month) == 8) && day == 15) {
- message = "中秋";
- } else if ((month == 9) && day == 9) {
- message = "重阳";
- } else if ((month == 12) && day == 8) {
- message = "腊八";
- } else {
- if (month == 12) {
- if ((((monthDays(year, month) == 29) && day == 29))
- || ((((monthDays(year, month) == 30) && day == 30)))) {
- message = "除夕";
- }
- }
- }
- return message;
- }
2.3 控件,可以用两层Recycleview,但最好不要这样做,嵌套体验是非常差的,明显的卡顿。所以尽量用一个Recycleview,利用getItemViewType来避免嵌套。
- @Override
- public int getItemViewType(int position) {
- if (isEmptyPosition(position)) {
- // 空布局
- return TYPE_EMPTY;
- }
- mTempPosition = position;
- int groupPosition = getGroupPositionForPosition(position);
- int type = judgeType(position);
- if (type == TYPE_HEADER) {
- return getHeaderViewType(groupPosition);
- } else if (type == TYPE_FOOTER) {
- return getFooterViewType(groupPosition);
- } else if (type == TYPE_CHILD) {
- int childPosition = getChildPositionForPosition(groupPosition, position);
- return getChildViewType(groupPosition, childPosition);
- }
- return super.getItemViewType(position);
- }
三, 核心源码
3.1 项目结构
3.2 CalendarSelectDialog.java
- public class CalendarSelectDialog extends Dialog {
- private ImageView icClose;
- private RecyclerView rvCalendar;
- private TextView tvSure;
-
-
- private Activity context;
-
- private CalendarGroupedListAdapter groupedListAdapter;
- private List<MonthEntity> monthList = new ArrayList<>();
-
- private int year, month, day;
- private int nowDay;
- private int lastDateSelect = -1, lastMonthSelect = -1;
-
- public interface OnViewClickLiatener {
- void sureClick(String selectTime);
-
- void cancelClick();
- }
-
- public OnViewClickLiatener onViewClickLiatener;
-
- public void setOnViewClickLiatener(OnViewClickLiatener onViewClickLiatener) {
- this.onViewClickLiatener = onViewClickLiatener;
- }
-
-
- public CalendarSelectDialog(Activity context) {
- super(context, R.style.custom_dialog2);
- this.context = context;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.dialog_caledar_select);
- setCanceledOnTouchOutside(true);
- WindowManager.LayoutParams params = getWindow().getAttributes();
- params.width = ScreenUtils.getScreenWidth(context);
- params.height = (int) (ScreenUtils.getTotalScreenHeight(context)*0.85f);
- getWindow().setGravity(Gravity.BOTTOM);
- getWindow().setAttributes(params);
- getWindow().setBackgroundDrawableResource(R.color.transparent);
- getWindow().setWindowAnimations(R.style.pop_animation_bottom);
- initView();
- setData();
-
- }
-
- public void initView() {
- icClose = (ImageView) findViewById(R.id.ic_close);
- rvCalendar = (RecyclerView) findViewById(R.id.rv_calendar);
- tvSure = (TextView) findViewById(R.id.tv_sure);
-
- }
-
- public void setData() {
- icClose.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- dismiss();
- if (onViewClickLiatener != null) {
- onViewClickLiatener.cancelClick();
- }
- }
- });
- tvSure.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if(lastMonthSelect<0){
- ToastHelp.showToast("请选择日期");
- return;
- }
- dismiss();
- MonthEntity monthEntity=monthList.get(lastMonthSelect);
- DateEntity dateEntity=monthEntity.getList().get(lastDateSelect);
- int year=monthEntity.getYear();
- int month=monthEntity.getMonth();
- int date=dateEntity.getDate();
-
- String monthString;
- if(month<10){
- monthString="0"+month;
- }else {
- monthString=String.valueOf(month);
- }
-
- String dataString;
- if(date<10){
- dataString="0"+date;
- }else {
- dataString=String.valueOf(date);
- }
-
- String selectTime=year+"-"+monthString+"-"+dataString;
- if (onViewClickLiatener != null) {
- onViewClickLiatener.sureClick(selectTime);
- }
- }
- });
- CalendarUtils.init(context);
- initCalendarData();
- initCalendarRv();
- }
-
-
-
- @Override
- public void dismiss() {
- if (context == null || ((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
- return;
- }
- super.dismiss();
- }
-
- @Override
- public void show() {
- if (context == null || ((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
- return;
- }
- super.show();
- }
-
-
- private void initCalendarData() {
- Calendar calendar = Calendar.getInstance();
- year = calendar.get(Calendar.YEAR);
- month = calendar.get(Calendar.MONTH);
- day = calendar.get(Calendar.DAY_OF_MONTH);
- nowDay = day;
- calendar.set(year, month, 1);
-
- for (int i = 0; i < 12; i++) {
- List<DateEntity> deList = new ArrayList<>();
- MonthEntity monthEntity = new MonthEntity();
- int maxDayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
- int empty = calendar.get(Calendar.DAY_OF_WEEK);
- empty = empty == 1 ? 6 : empty - 2;
- for (int j = 0; j < empty; j++) {
- DateEntity de = new DateEntity();
- de.setType(1);
- deList.add(de);
- }
- for (int j = 1; j <= maxDayOfMonth; j++) {
- DateEntity de = new DateEntity();
- if (i == 0) {
- de.setType(j < nowDay ? 4 : 0);
- } else {
- de.setType(0);
- }
-
- de.setDate(j);
- if (i == 0 && nowDay == j) {
- de.setToday(true);
- } else {
- de.setToday(false);
- }
- de.setParentPos(i);
- String[] result=DatePickerUtils.getLunarDate(year, month + 1, j);
- de.setDesType(result[0]);
- de.setDesc(result[1]);
- deList.add(de);
- }
-
- year = calendar.get(Calendar.YEAR);
- month = calendar.get(Calendar.MONTH) + 1;
- monthEntity.setTitle(year + "年" + month + "月");
- monthEntity.setYear(year);
- monthEntity.setMonth(month);
- monthEntity.setList(deList);
- monthList.add(monthEntity);
-
- calendar.add(Calendar.MONTH, 1);
- }
-
- }
-
- private void initCalendarRv() {
- groupedListAdapter =new CalendarGroupedListAdapter(context,monthList);
- GroupedGridLayoutManager gridLayoutManager = new GroupedGridLayoutManager(context, 7, groupedListAdapter);
- rvCalendar.setLayoutManager(gridLayoutManager);
- rvCalendar.getItemAnimator().setChangeDuration(0);
- rvCalendar.setAdapter(groupedListAdapter);
- groupedListAdapter.setOnItemClickListener(new CalendarGroupedListAdapter.OnItemClickListener() {
- @Override
- public void itemClick(int groupPosition, int childPosition) {
- //setRangeClick(groupPosition,childPosition);
- setSingleClick(groupPosition,childPosition);
- }
- });
- }
-
- private void getViews() {
- rvCalendar = (RecyclerView) findViewById(R.id.rv_calendar);
- }
-
- /**
- *
- * @param groupPosition
- * @param childPosition
- */
- private void setSingleClick(int groupPosition, int childPosition){
- if (groupPosition == lastMonthSelect && childPosition == lastDateSelect) {
- return;
- }
-
- monthList.get(groupPosition).getList().get(childPosition).setType(8);
-
- groupedListAdapter.notifyChildChanged(groupPosition, childPosition);
- if (lastDateSelect != -1) {
- monthList.get(lastMonthSelect).getList().get(lastDateSelect).setType(0);
- groupedListAdapter.notifyChildChanged(lastMonthSelect, lastDateSelect);
- }
- lastMonthSelect = groupPosition;
- lastDateSelect = childPosition;
- }
-
- /**
- * 范围选择
- */
- private boolean selectComplete;
- private List<Integer> selectMonth = new ArrayList<>();
- private List<Integer> selectDate = new ArrayList<>();
- private void setRangeClick(int parentPos, int pos){
- if (parentPos != lastMonthSelect || pos != lastDateSelect) {
-
- //1、第二次选择;2、选择的月份相等日期比之前选择的大或者选择的月份比之前的大;3、选择未完成
- boolean haveMiddle = lastMonthSelect != -1 && ((lastMonthSelect == parentPos && pos > lastDateSelect) || (parentPos > lastMonthSelect))
- && !selectComplete;
- if (haveMiddle) {
- monthList.get(parentPos).getList().get(pos).setType(6);
- selectDate.add(1);
- monthList.get(lastMonthSelect).getList().get(lastDateSelect).setType(7);
- selectDate.add(1);
-
- int monthLen = parentPos - lastMonthSelect;
- List<DateEntity> list;
- int dateLen;
- if (monthLen == 0) {
- dateLen = pos - lastDateSelect;
- for (int i = 1; i < dateLen; i++) {
- monthList.get(parentPos).getList().get(i + lastDateSelect).setType(5);
- selectDate.add(1);
- }
- groupedListAdapter.notifyGroupChanged(lastMonthSelect);
- //选择了这个月
- selectMonth.add(parentPos);
- } else {
- //第一个月
- int lastMonthSize = monthList.get(lastMonthSelect).getList().size();
- dateLen = lastMonthSize - lastDateSelect;
- for (int i = 1; i < dateLen; i++) {
- monthList.get(lastMonthSelect).getList().get(i + lastDateSelect).setType(5);
- selectDate.add(1);
- }
- groupedListAdapter.notifyGroupChanged(lastMonthSelect);
- //选择了这个月
- selectMonth.add(lastMonthSelect);
-
- //中间月份
- int month;
- int middleMonthLen = parentPos - lastMonthSelect;
- for (int i = 1; i < middleMonthLen; i++) {
- month = lastMonthSelect + i;
- list = monthList.get(month).getList();
- dateLen = list.size();
- for (int j = 0; j < dateLen; j++) {
- if (list.get(j).getType() != 1) {
- list.get(j).setType(5);
- selectDate.add(1);
- }
- }
- groupedListAdapter.notifyGroupChanged(month);
- //选择了这个月
- selectMonth.add(month);
- }
-
- //最后那个月
- dateLen = pos;
- for (int i = 0; i < dateLen; i++) {
- DateEntity de = monthList.get(parentPos).getList().get(i);
- if (de.getType() != 1) {
- de.setType(5);
- selectDate.add(1);
- }
- }
- groupedListAdapter.notifyGroupChanged(parentPos);
- //选择了这个月
- selectMonth.add(parentPos);
- }
- Log.d("mita", "选择的天数:" + selectDate.size());
- selectComplete = true;
- lastMonthSelect = -1;
- lastDateSelect = -1;
- } else {
- selectDate.clear();
-
- //清除已选
- if (selectComplete) {
- List<DateEntity> list;
- DateEntity de;
- int len = selectMonth.size();
- for (int i = 0; i < len; i++) {
- list = monthList.get(selectMonth.get(i)).getList();
- int size = list.size();
- for (int j = 0; j < size; j++) {
- de = list.get(j);
- if (de.getType() == 5 || de.getType() == 6 || de.getType() == 7) {
- de.setType(0);
- }
- }
- groupedListAdapter.notifyGroupChanged(selectMonth.get(i));
- }
- selectMonth.clear();
- }
-
- monthList.get(parentPos).getList().get(pos).setType(3);
- groupedListAdapter.notifyGroupChanged(parentPos);
- if (lastDateSelect != -1) {
- monthList.get(lastMonthSelect).getList().get(lastDateSelect).setType(0);
- groupedListAdapter.notifyGroupChanged(lastMonthSelect);
- }
- lastMonthSelect = parentPos;
- lastDateSelect = pos;
- selectComplete = false;
- }
- }
- }
- }
3.2 CalendarGroupedListAdapter.java
- public class CalendarGroupedListAdapter extends GroupedRecyclerViewAdapter {
-
-
- private List<MonthEntity> groupList;
- private Context context;
-
- public CalendarGroupedListAdapter(Context context, List<MonthEntity> groupList) {
- super(context);
- this.context = context;
- this.groupList = groupList;
- }
-
- @Override
- public int getGroupCount() {
- return groupList.size();
- }
-
- @Override
- public int getChildrenCount(int groupPosition) {
- return groupList.get(groupPosition).getList().size();
- }
-
- @Override
- public boolean hasHeader(int groupPosition) {
- return true;
- }
-
- @Override
- public boolean hasFooter(int groupPosition) {
- return false;
- }
-
- @Override
- public int getHeaderLayout(int viewType) {
- return R.layout.item_calendar;
- }
-
- @Override
- public int getFooterLayout(int viewType) {
- return 0;
- }
-
- @Override
- public int getChildLayout(int viewType) {
- return R.layout.item_date;
- }
-
- @Override
- public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
- MonthEntity monthEntity = groupList.get(groupPosition);
- holder.setText(R.id.tv_cal_title, monthEntity.getTitle());
-
- }
-
- @Override
- public void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition) {
-
- }
-
- @Override
- public void onBindChildViewHolder(BaseViewHolder holder, final int groupPosition, final int childPosition) {
- DateEntity dateEntity = groupList.get(groupPosition).getList().get(childPosition);
-
-
- LinearLayout llDate = holder.get(R.id.ll_date);
- TextView mTvDate = holder.get(R.id.tv_date);
- TextView mTvDesc = holder.get(R.id.tv_desc);
- TextView mTvToday = holder.get(R.id.tv_today);
- mTvToday.setText("今日");
-
- int date = dateEntity.getDate();
- int type = dateEntity.getType();
- boolean isToday = dateEntity.isToday();
- if (type == 1) {//留白
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvToday.setTextColor(Color.TRANSPARENT);
- mTvDate.setText("");
- mTvDesc.setText("");
- mTvDate.setTextColor(Color.TRANSPARENT);
- mTvDesc.setTextColor(Color.TRANSPARENT);
- llDate.setBackgroundColor(Color.TRANSPARENT);
- llDate.setEnabled(false);
- } else if (type == 0) {//日常
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText(dateEntity.getDesc());
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.color_red));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.color_333333));
- mTvDesc.setTextColor(TextUtils.isEmpty(dateEntity.getDesType()) ? ContextCompat.getColor(context, R.color.color_333333) : ContextCompat.getColor(context, R.color.color_red));
- llDate.setBackgroundColor(Color.TRANSPARENT);
- llDate.setEnabled(true);
- } else if (type == 3) {//日常选中
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText(dateEntity.getDesc());
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.white));
- llDate.setBackgroundResource(R.drawable.state_selected);
- llDate.setClickable(true);
- } else if (type == 4) {//今天之前的日期
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText(dateEntity.getDesc());
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.color_cccccc));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.color_cccccc));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.color_cccccc));
- llDate.setBackgroundColor(Color.TRANSPARENT);
- llDate.setEnabled(false);
- } else if (type == 5) {//中间
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText(dateEntity.getDesc());
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.white));
- llDate.setBackgroundResource(R.drawable.state_middle_range);
- llDate.setEnabled(true);
- } else if (type == 6) {//终点
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText("结束");
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.white));
- llDate.setBackgroundResource(R.drawable.state_end_range);
- llDate.setEnabled(true);
- } else if (type == 7) {//起点
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText("开始");
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.white));
- llDate.setBackgroundResource(R.drawable.state_first_range);
- llDate.setEnabled(true);
- } else if (type == 8) {//单选
- mTvToday.setVisibility(isToday ? View.VISIBLE : View.INVISIBLE);
- mTvDate.setText(String.valueOf(dateEntity.getDate()));
- mTvDesc.setText(dateEntity.getDesc());
- mTvToday.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDate.setTextColor(ContextCompat.getColor(context, R.color.white));
- mTvDesc.setTextColor(ContextCompat.getColor(context, R.color.white));
- llDate.setBackgroundResource(R.drawable.state_selected);
- llDate.setEnabled(true);
- }
-
- llDate.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (onItemClickListener != null) {
- onItemClickListener.itemClick(groupPosition, childPosition);
- }
- }
- });
- }
-
- public interface OnItemClickListener {
- void itemClick(int groupPosition, int childPosition);
- }
-
- public OnItemClickListener onItemClickListener;
-
- public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
- this.onItemClickListener = onItemClickListener;
- }
- }
四,注意
4.1 由于左右留白,父控件Recycleview做了外边距margin,会导致子控件左右也有边距。但UI要求是无边距的,这个时候就需要特殊处理控件。
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/rv_calendar"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:overScrollMode="never"/>
4.2 方法,可以用裁剪属性clipChildren,来控制他的子控件是否要在他应有的边界内进行绘制
android:clipChildren=“false” 就是不限制他子控件在其边界内进行绘制
android:clipChildren=“true” 限制他子控件在其边界内进行绘制
4.3 clipChildren需要特别注意,加在RecyclerView父控件是没用的,只能加载RecyclerView的父控件,即需要需要裁剪的view的爷辈控件。如下:添加属性android:clipChildren="false"
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:clipChildren="false">
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/rv_calendar"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:overScrollMode="never"/>
-
- </FrameLayout>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。