Android 纵向双选日历

这个日历的布局分两部分,一部分是显示星期几的LinearLayout,另外就是一个RecyclerView,负责纵向滚动了。

纵向双选日历

工具类:

implementation 'com.blankj:utilcode:1.17.3'

上activity_calendar代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="5dp"android:text="" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never" />
</LinearLayout>

接下来是CalendarActivity

  1. 计算数据
  2. 可以扩展日历的点击事件和范围选择事件
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.blankj.utilcode.constant.TimeConstants;
import com.blankj.utilcode.util.TimeUtils;import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;public class CalendarActivity extends AppCompatActivity {private RecyclerView recyclerView;private CalendarRangeAdapter calendarRangeAdapter;/*** 最大月份数*/private int maxMonth = 12;private List<DateBean> dateList = new ArrayList<>();private List<DateBean> allDateList = new ArrayList<>();private Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {initView();super.handleMessage(msg);}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_calendar);recyclerView = findViewById(R.id.recycler_view);new Thread() {@Overridepublic void run() {initData();};}.start();}private void initView() {GridLayoutManager manager = new GridLayoutManager(CalendarActivity.this, 7);manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {return allDateList.get(position).getType() == 0 ? 7 : 1;}});recyclerView.setLayoutManager(manager);calendarRangeAdapter = new CalendarRangeAdapter(CalendarActivity.this, allDateList);recyclerView.setAdapter(calendarRangeAdapter);calendarRangeAdapter.setOnItemSelect(new CalendarRangeAdapter.OnItemSelect() {@Overridepublic void onItemClick(int position) {}@Overridepublic void onItemRangeSelect(String startDate, String endDate) {System.out.println(startDate + "~" + endDate);}});}private void initData() {for (int i = 0; i < maxMonth; i++) {Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MONTH, i);int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH) + 1;int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);String dateString = simpleDateFormat.format(calendar.getTime());DateBean monthBean = new DateBean();monthBean.setDate(dateString.substring(0, 7));monthBean.setCanSelect(false);monthBean.setType(0);dateList.clear();dateList.add(monthBean);calendar.set(Calendar.DAY_OF_MONTH, 1);//当月第一天是周几 0是周日,1是周一 以此类推int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);//填充1号前面的空白for (int j = 0; j < dayOfWeek - 1; j++) {DateBean dateBean = new DateBean();dateBean.setCanSelect(false);dateBean.setType(1);dateBean.setDate("");dateList.add(dateBean);}for (int j = 0; j < maxDays; j++) {DateBean dateBean = new DateBean();dateBean.setType(1);dateBean.setCenterString(String.valueOf(j + 1));dateBean.setSelect(true);dateBean.setDate(year + "-" + addZero(month) + "-" + addZero(j + 1));//今天之前不可选中if (TimeUtils.getTimeSpanByNow(dateBean.getDate(), new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA), TimeConstants.DAY) < 0) {dateBean.setCenterString(String.valueOf(j + 1));dateBean.setCanSelect(false);} else {if (TimeUtils.getTimeSpanByNow(dateBean.getDate(), new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA), TimeConstants.DAY) > 0) {dateBean.setCenterString(String.valueOf(j + 1));} else {dateBean.setCenterString("今天");}dateBean.setCanSelect(true);}dateList.add(dateBean);}allDateList.addAll(dateList);}Message msg = handler.obtainMessage();handler.sendMessage(msg);}private String addZero(int text) {if (text < 10) {return "0" + text;} else {return "" + text;}}
}

上CalendarRangeAdapter代码(根据bean属性操作):

  1. 根据类型,填充月布局和日布局。
  2. 包含点击、范围选择的方法
public class CalendarRangeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {private Context context;private List<DateBean> list;private int[] selectRange = new int[2];private final int TYPE_MONTH = 0;private final int TYPE_DAY = 1;public CalendarRangeAdapter(Context context, List<DateBean> list) {this.context = context;this.list = list;initSelect();}public void initSelect() {clearSelect();}public void clearSelect() {for (int i = 0; i < list.size(); i++) {list.get(i).setSelect(false);list.get(i).setSelectRange(false);list.get(i).setBottomString("");}selectRange[0] = -1;selectRange[1] = -1;}public void notifySelect() {notifyDataSetChanged();}public void setData(List<DateBean> list) {this.list = list;notifyDataSetChanged();}@NonNull@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {RecyclerView.ViewHolder holder = null;if (viewType == 0) {//月份View view = LayoutInflater.from(context).inflate(R.layout.item_month,parent, false);holder = new MonthViewHolder(view);} else {//日期View view = LayoutInflater.from(context).inflate(R.layout.item_day,parent, false);holder = new DayViewHolder(view);}return holder;}@Overridepublic void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {final int fPosition = holder.getAdapterPosition();if (holder instanceof MonthViewHolder) {((MonthViewHolder) holder).tvMonth.setText(list.get(position).getDate().replace("-", "年") + "月");} else {final DayViewHolder viewHolder = (DayViewHolder) holder;viewHolder.tvCenter.setText(list.get(fPosition).getCenterString());viewHolder.tvBottom.setText(list.get(fPosition).getBottomString());if (viewHolder.llDay.getTag() instanceof View.OnClickListener){viewHolder.llDay.setOnClickListener( null);}if (list.get(fPosition).isCanSelect()) {//今天之前(不可选)if (TimeUtils.getTimeSpanByNow(list.get(position).getDate(), new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA), TimeConstants.DAY) < 0) {viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_can_not_select));} else {if (TimeUtils.getTimeSpanByNow(list.get(position).getDate(), new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA), TimeConstants.DAY) > 0) {viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_can_select));} else {viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_today));}if (list.get(fPosition).isSelect()) {viewHolder.llDay.setBackgroundColor(ContextCompat.getColor(context, R.color.color_calendar_background_select));viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_select));viewHolder.tvBottom.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_select));} else if (list.get(fPosition).isSelectRange()) {viewHolder.llDay.setBackgroundColor(ContextCompat.getColor(context, R.color.color_calendar_background_select_range));viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_select));viewHolder.tvBottom.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_select));} else {viewHolder.llDay.setBackgroundColor(ContextCompat.getColor(context, R.color.color_calendar_background_normal));}if (onItemSelect != null) {View.OnClickListener clickListener =    new View.OnClickListener() {@Overridepublic void onClick(View v) {if (selectRange[0] == -1 && selectRange[1] == -1) {selectRange[0] = fPosition;list.get(fPosition).setSelect(true);list.get(fPosition).setBottomString("开始");onItemSelect.onItemClick(fPosition);notifyDataSetChanged();} else if (selectRange[0] != -1 && selectRange[1] == -1) {onItemSelect.onItemClick(fPosition);if (fPosition < selectRange[0]) {clearSelect();selectRange[0] = fPosition;list.get(fPosition).setSelect(true);list.get(fPosition).setBottomString("开始");} else if (fPosition > selectRange[0]) {selectRange[1] = fPosition;list.get(fPosition).setSelect(true);list.get(fPosition).setBottomString("结束");for (int i = selectRange[0] + 1; i < selectRange[1]; i++) {list.get(i).setSelectRange(true);list.get(i).setBottomString("");}onItemSelect.onItemRangeSelect(list.get(selectRange[0]).getDate(), list.get(selectRange[1]).getDate());} else {clearSelect();}notifyDataSetChanged();} else {clearSelect();selectRange[0] = fPosition;list.get(fPosition).setSelect(true);list.get(fPosition).setBottomString("开始");onItemSelect.onItemClick(fPosition);notifyDataSetChanged();}}};viewHolder.llDay.setOnClickListener(clickListener);viewHolder.llDay.setTag(clickListener);}}} else {viewHolder.llDay.setBackgroundColor(ContextCompat.getColor(context, R.color.color_calendar_background_normal));viewHolder.tvCenter.setTextColor(ContextCompat.getColor(context, R.color.color_calendar_can_not_select));}}}public OnItemSelect onItemSelect;public void setOnItemSelect(OnItemSelect onItemSelect) {this.onItemSelect = onItemSelect;}public interface OnItemSelect {void onItemClick(int position);void onItemRangeSelect(String startDate, String endDate);}@Overridepublic int getItemViewType(int position) {return list.get(position).getType() == 0 ? TYPE_MONTH : TYPE_DAY;}@Overridepublic int getItemCount() {return list == null ? 0 : list.size();}class MonthViewHolder extends RecyclerView.ViewHolder {TextView tvMonth;public MonthViewHolder(View itemView) {super(itemView);tvMonth = itemView.findViewById(R.id.tv_month);}}class DayViewHolder extends RecyclerView.ViewHolder {LinearLayout llDay;TextView tvCenter;TextView tvBottom;public DayViewHolder(View itemView) {super(itemView);llDay = itemView.findViewById(R.id.ll_day);tvCenter = itemView.findViewById(R.id.tv_center);tvBottom = itemView.findViewById(R.id.tv_bottom);}}
}

DateBean代码(中间文字,底部文字,是否可选等属性):

public class DateBean {/*** 日期*/private String date;/*** 底部文字*/private String bottomString;/*** 中间文字*/private String centerString;/*** 是否可以选择*/private boolean canSelect;/*** 是否选中*/private boolean isSelect;/**是否在选中范围*/private boolean isSelectRange;/*** item type 0月份 1日期*/private int type;public String getDate() {return date == null ? "" : date;}public void setDate(String date) {this.date = date;}public String getCenterString() {return centerString == null ? "" : centerString;}public void setCenterString(String centerString) {this.centerString = centerString;}public boolean isCanSelect() {return canSelect;}public void setCanSelect(boolean canSelect) {this.canSelect = canSelect;}public boolean isSelect() {return isSelect;}public void setSelect(boolean select) {isSelect = select;}public boolean isSelectRange() {return isSelectRange;}public void setSelectRange(boolean selectRange) {isSelectRange = selectRange;}public int getType() {return type;}public void setType(int type) {this.type = type;}public String getBottomString() {return bottomString == null ? "" : bottomString;}public void setBottomString(String bottomString) {this.bottomString = bottomString;}
}

上color.xml(可以自己换):

<resources><color name="color_calendar_can_not_select">#dedede</color><color name="color_calendar_can_select">#505050</color><color name="color_calendar_select">#ffffff</color><color name="color_calendar_today">#F67332</color><color name="color_calendar_background_select">#F3BE30</color><color name="color_calendar_background_select_range">#7DF3BE30</color><color name="color_calendar_background_normal">#00000000</color>
</resources>

OK,完毕!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/812355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

研究了一款Vue2开发的Markdown编辑器

最近突然喜欢开始写作了&#xff0c;写笔记&#xff0c;写日记&#xff0c;写总结&#xff0c;各种写。所以&#xff0c;想要打造一个自己喜欢的编辑器&#xff0c;于是开始研究。 首先来看看我从Github丄扒拉到的这个开源的代码&#xff1a; 运行起来以后效果是这样的&…

探究C++20协程(1)——C++协程概览

什么是协程&#xff1f; 协程就是一段可以挂起&#xff08;suspend&#xff09;和恢复&#xff08;resume&#xff09;的程序&#xff0c;一般而言&#xff0c;就是一个支持挂起和恢复的函数。 一般情况下&#xff0c;函数一旦开始&#xff0c;就无法暂停。如果一个函数能够暂…

用于扩展Qt自身的插件(下)

扩展Qt自身的插件 引言必须满足项创建插件示例代码生成插件配置加载插件的环境创建使用插件的项目配置库和头文件依赖的步骤:应用程序代码运行结果总结引言 本文继上篇的扩展Qt自身的插件,接着记录Qt自身的插件,只不过本文提及的用于扩展Qt自身的插件是可以在QtCreator的设…

走进MySQL:从认识到入门(针对初学者)

一&#xff0c;引言 MySQL是一款久负盛名且广泛应用的关系型数据库管理系统&#xff0c;自1995年Michael Widenius和David Axmark在瑞典和芬兰发起研发以来&#xff0c;其发展历程可谓辉煌且深远。作为开源软件的代表&#xff0c;MySQL以其卓越的成本效益、高性能及高可靠性赢得…

关于 Amazon DynamoDB 的学习和使用

文章主要针对于博主自己的技术栈&#xff0c;从Unity的角度出发&#xff0c;对于 DynamoDB 的使用。 绿色通道&#xff1a; WS SDK for .NET Version 3 API Reference - AmazonDynamoDBClient Amazon DynamoDB Amazon DynamoDB is a fast, highly scalable, highly available,…

Harmony鸿蒙南向驱动开发-RTC接口使用

功能简介 RTC&#xff08;real-time clock&#xff09;为操作系统中的实时时钟设备&#xff0c;为操作系统提供精准的实时时间和定时报警功能。当设备下电后&#xff0c;通过外置电池供电&#xff0c;RTC继续记录操作系统时间&#xff1b;设备上电后&#xff0c;RTC提供实时时…

【Java SE】11.认识异常

目录 1.异常的概念与体系结构 1.1异常的概念 1.2异常的体系结构 1.3异常的分类 2.异常的处理 2.1防御式编程 2.2异常的抛出 2.3异常的捕获 2.3.1异常声明throws 2.3.2try-catch捕获并处理 2.3.3finally 2.4异常的处理流程 3.自定义异常类 1.异常的概念与体系结构 …

MAC OS关闭SIP(navicat 无法保存密码)

最近安装navicat&#xff08;16.3.7&#xff09;时,安装后无法保存密码,保存密码会报错如下&#xff1a; 因为用的破解版&#xff0c;一开始是打不开的&#xff0c;用自带的修复软件修复后就可以打开了&#xff0c;但是保存密码就会报错&#xff0c;按照网上的一些操作 1、卸载…

蓝桥杯嵌入式(G431)备赛笔记——RTC

// RTC time// 声明一个变量 rtc_tick 用于记录上次 RTC 处理的时间 u32 rtc_tick 0;// 声明结构体变量 D 用于存储 RTC 的日期信息 RTC_DateTypeDef D;// 声明结构体变量 T 用于存储 RTC 的时间信息 RTC_TimeTypeDef T;// RTC_proc 函数&#xff0c;用于处理 RTC 时间 void R…

Github 2024-04-10 C开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10Shell项目1Python项目1Git - 快速、可扩展、分布式的版本控制系统 创建周期:5740 天开发语言:C, Shell协议类型:OtherStar数量:4955…

.NET 设计模式—享元模式(Flyweight Pattern)

简介 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它旨在减少系统中相似对象的内存占用或计算开销&#xff0c;通过共享相同的对象来达到节省资源的目的。 享元模式提供了一种高效地共享对象的方式&#xff0c;从而减少了内存占用和提…

vue3-video-play 在安卓上正常播放,在ios上不能播放,问题解决

1.ios上autoplay需要静音&#xff0c;在播放后再打开声音 <vue3videoPlay v-if"!isComponent" v-bind"options" :playsinline"playsinline"></vue3videoPlay>let playsinline computed(() > {if (props.isComponent) {return}o…

【电路笔记】-异或门

异或门 文章目录 异或门1、概述2、数字逻辑异或门3、异或门等效电路异或逻辑函数是一个非常有用的电路,可用于许多不同类型的计算电路。 1、概述 异或门是算术运算中常用的另一种数字逻辑门,因为它可以用来给出两个二进制数的和以及错误检测和纠正电路。 在前面的文章中,我…

Photoshop 2023 中文---创意与设计的新篇章

Photoshop 2023是由Adobe Systems开发和发行的一款强大的图像处理软件&#xff0c;广泛应用于专业摄影师、设计师、艺术家等用户群体。它拥有丰富的功能和工具&#xff0c;可以轻松进行图像编辑、合成、调整和修复等任务。在Photoshop 2023中&#xff0c;智能选择功能得到了升级…

python爬虫-------urllib代理和代理池(第十七天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Kubernetes(k8s):深入理解k8s中的亲和性(Affinity)及其在集群调度中的应用

Kubernetes&#xff08;k8s&#xff09;&#xff1a;深入理解k8s中的亲和性&#xff08;Affinity&#xff09;及其在集群调度中的应用 1、什么是亲和性&#xff1f;2、节点亲和性&#xff08;Node Affinity&#xff09;2.1 硬性节点亲和性规则&#xff08;required&#xff09;…

paddle实现手写数字模型(一)

参考文档&#xff1a;paddle官网文档环境&#xff1a;Python 3.12.2 &#xff0c;pip 24.0 &#xff0c;paddlepaddle 2.6.0 python -m pip install paddlepaddle2.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple调试代码如下&#xff1a; LeNet.py import paddle import p…

013_NaN_in_Matlab中的非数与调试方法

Matlab中的非数与调试方法 是什么&#xff1f; Matlab编程&#xff08;计算器使用&#xff09;中经常有个错误给你&#xff0c;这句话里可能包含一个关键词NaN。大部分学生都有过被 NaN 支配的痛苦记忆。 NaN 是 Not a Number 的缩写&#xff0c;表示不是一个数字。在 Matla…

【SVN】clean up报错:Cleanup failed to process the following paths 解决方法

报错来源&#xff1a;代码更新有一个文件既不能接受自己的也不能接受别人的&#xff0c;只能取消&#xff0c;再提交提醒clean up&#xff0c;随后报标题错误。 解决方法&#xff1a;参考https://www.cnblogs.com/pinpin/p/11395438.html 注&#xff1a;如果clean up的时候有…

基于ssm项目校园快递平台系统

采用技术 基于SpringBoot框架实现的web的智慧社区系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 管理员功能 订单管理 快递管理 公告管理 公告类…