Android Kotlin Java 自定义日历控件 CalendarView ,支持单选,多选,按星期选,跨月份日期范围选择,样式设置

GitHub 源码地下载

https://github.com/hdev0225/CalendarView

CalendarView 日历控件

CalendarView 使用kotlin语言开发,支持单选,多选,按星期选,跨月份日期范围选择,样式设置

设置不可选择日期,设置只可选择某些日期

运行环境

AS 版本: Android Studio Dolphin | 2021.3.1

Android Gradle Plugin Version: 7.3.0

Gradle Version: 7.5

示例

Demo

安装

1、添加JitPack仓库到根路径下的build.gradle

allprojects {
    repositories {
        // ...
        maven { url 'https://jitpack.io' }
    }
}

2、添加依赖到模块中的build.gradle

dependencies {
    implementation 'com.github.hdev0225:CalendarView:v1.0.5'
}

日历功能简介

  • 简单应用
  • 单选日历
  • 多选日历
  • 按星期选择日历
  • 日期范围选择
  • 设置样式
  • 设置不可选择日期列表
  • 设置只可选择某些日期列表

简单示例

默认情况下:开始日期为1970-1-1,结束日期为手机时间,并选中当前时间

<com.hdev.calendar.view.SingleCalendarView
    android:id="@+id/calendar_view"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    android:layout_margin="15dp"
    android:background="@drawable/bg" />

单选日历

single.gif
<com.hdev.calendar.view.SingleCalendarView
    android:id="@+id/calendar_view"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    android:layout_margin="15dp"
    android:background="@drawable/bg" />
val calendarView: SingleCalendarView = findViewById(R.id.calendar_view)
// 事件监听        
calendarView.setOnSingleDateSelectedListener {
_, dateInfo ->
Toast.makeText(this@SingleActivity, dateInfo.toString(), Toast.LENGTH_LONG).show()}
// 开始日期        
var startDate = DateInfo(2023, 1, 15)
// 结束日期        
val endDate = DateInfo(2023, 4, 15)
// 选中2023-1-1
val selectedDate = DateInfo(2023, 1, 1)
// 初始化,设置日期范围
calendarView.setDateRange(
    startDate.timeInMillis(),
    endDate.timeInMillis(),
    selectedDate.timeInMillis()
)

多选日历

multi.gif
<com.hdev.calendar.view.MultiCalendarView
    android:id="@+id/calendar_view"
    android:layout_width="wrap_content"
    android:layout_height="400dp"
    android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp"
    android:background="@drawable/bg" />

val dateList = mutableListOf<DateInfo>()
dateList.add(DateInfo(2023, 5, 3))
dateList.add(DateInfo(2023, 5, 8))
dateList.add(DateInfo(2023, 5, 5))

val calendarView: MultiCalendarView = findViewById(R.id.calendar_view)
calendarView.setOnMultiDateSelectedListener {
_, clickedDate, dateList ->
}
// 设置选中日期列表
calendarView.selectedDateList = dateList

按星期选择

week.gif
<com.hdev.calendar.view.WeekCalendarView
    android:id="@+id/calendar_view"
    android:layout_width="match_parent"
    android:layout_height="420dp"
    android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp" />
// 开始日期
val startDate = DateInfo(2021, 12, 30)
// 结束日期        
val endDate = DateInfo(2023, 4, 15)
// 设置某一天,该星期会选中
val selectedDate = DateInfo(2022, 1, 1)

val calendarView: WeekCalendarView = findViewById(R.id.calendar_view)
// 事件监听        
calendarView.setOnDateRangeSelectedListener {
_, selecteDate, startDate, endDate ->
Toast.makeText(this@WeekActivity, "start: $startDate, end:$endDate", Toast.LENGTH_LONG).show()
}

日期范围选择

range.gif
 <com.hdev.calendar.view.RangeCalendarView
       android:id="@+id/calendar_view"
       android:layout_width="match_parent"
       android:layout_height="400dp"
       android:layout_marginLeft="10dp"
       android:layout_marginRight="10dp"
       android:background="#ffffff"
       app:header_view="com.hdev.calendar.view.DefaultRangeHeaderView"
       app:selected_bg_color="#0078D7"
       app:selected_end_bg_color="#ff0000"
       app:selected_end_day_color="#ffffff"
       app:selected_range_bg_color="#88ff0000"
       app:selected_range_day_color="#ffffff"
       app:selected_start_bg_color="#ff0000"
       app:selected_start_day_color="#ffffff" />
val calendarView: RangeCalendarView = findViewById(R.id.calendar_view)
// 设置日期范围        
calendarView.setSelectedDateRange(DateInfo(2023, 2, 21), DateInfo(2023, 5, 13))
// 事件监听
calendarView.setOnDateRangeSelectedListener {
_, // 日历控件
_, // 选中的日期
startDate: DateInfo, // 开始日期
endDate: DateInfo -> // 结束日期
Toast.makeText(this@RangeActivity, "${startDate.format()}---${endDate.format()}", Toast.LENGTH_SHORT).show()
}

设置日历样式

style.gif
<com.hdev.calendar.view.SingleCalendarView
    android:id="@+id/calendar_view"
    android:layout_width="350dp"
    android:layout_height="335dp"
    android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp"
    android:background="@drawable/bg"
    app:day_font_size="16sp"
    app:default_color="#000000"
    app:default_dim_color="#AAAAAA"
    app:header_view="com.calendar.app.view.CustomHeaderView"
    app:selected_bg_color="#0078D7"
    app:selected_day_color="#EFEFEF"
    app:week_title_color="#ff0000"
    app:week_title_font_size="12sp"
    app:week_title_label="M、T、W、T、F、S、S"
    app:weekend_color="#F96A31" />

通用属性

header_view:头部,包名+类型,需要继承BaseHeaderView类,自定义头部

day_font_size:日期字体大小,eg: 16sp

week_title_color: 星期标题颜色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

week_title_font_size:星期标题字体大小, eg: 12sp;

week_title_label:星期标题,以顿号分割,如:一、二、三、四、五、六、日。起始星期为星期一;

default_color:默认文字颜色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

default_dim_color:默认文字灰色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

weekend_color:周未字体颜色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

selected_bg_color:选中背景色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

selected_day_color:选中日子颜色,类型:颜色码或者颜色引用, eg:#ffff00或者R.color.red;

selected_day_dim_color:范围选择或者按星期选择的日历时,该日期不能选择,但在范围或者星期之间, eg:#ffff00或者R.color.red;

日期范围属性

selected_range_bg_color:选中区间背景色,开始与结束之间的日期(不包括开始和结束日期), eg:#ffff00或者R.color.red;

selected_range_day_color:选中区间字体颜色,开始与结束之间的日期(不包括开始和结束日期), eg:#ffff00或者R.color.red;

selected_start_bg_color:开始日期背景色, eg:#ffff00或者R.color.red;

selected_start_day_color:开始日期字体颜色, eg:#ffff00或者R.color.red;

selected_end_bg_color:结束日期背景色, eg:#ffff00或者R.color.red;

selected_end_day_color:结束日期字体颜色, eg:#ffff00或者R.color.red;

设置不可选择日期

val dateList = mutableListOf<DateInfo>()
dateList.add(DateInfo(2023, 4, 8))
dateList.add(DateInfo(2023, 4, 11))
dateList.add(DateInfo(2023, 3, 31))
val calendarView: WeekCalendarView = findViewById(R.id.calendar_view)
// setup un-clickable date
calendarView.unClickableDateList = dateList

设置只可选择某些日期

val dateList = mutableListOf<DateInfo>()
dateList.add(DateInfo(2023, 4, 8))
dateList.add(DateInfo(2023, 4, 11))
dateList.add(DateInfo(2023, 3, 31))
val calendarView: WeekCalendarView = findViewById(R.id.calendar_view)
calendarView.clickableDateList = dateList

CalendarView方法说明

通用方法

unClickableDateList 设置不可点击的日期列表

clickableDateList 设置只能点击的日期列表

setDateRange 设置日期范围,参数:开始日期,结束日期,当前选中的日期

单先日历

setSelectedDate 设置选中某一天,如:点击按钮后,跳转到某一个日期

多选日历

selectedDateList 设置选中的日期列表/获取选中的日期列表

事件监听

/**
 * 单选接口回调
 */
OnSingleDateSelectedListener(
     view: SingleCalendarView, // 日历控件
     selectedDate: DateInfo // 选中的日期
)

/**
 * 按星期选,区域选择接口回调
 */
 OnDateRangeSelectedListener(
     view: BaseCalendarView, // 日历控件
     selectedDate: DateInfo, // 选中的日期
     startDate: DateInfo, // 开始日期
     endDate: DateInfo // 结束日期
)

/**
 * 多选
 */
OnMultiDateSelectedListener(
    view: MultiCalendarView, // 日历控件
    clickedDate: DateInfo, // 当前当点的日期,选中或者取消选中
    dateList: List<DateInfo>, // 日期列表
) 

DateInfo类说明

提供将dateInfo转calendar

将calendar转成dateInfo

将dateInfo转毫秒

BaseHeaderView说明

自定义头部,需要继承BaseHeaderView,更新标题,显示或者隐藏上下面,然后在xml布局文件中设置header_view,如下

app:header_view="com.calendar.app.view.CustomHeaderView"
/**
 * 获取布局id,如:R.layout.default_header_view
 */
protected abstract fun getLayoutId(): Int

/**
 * 更新标题
 */
open fun updateTitle(year: Int, month: Int) {}

/**
 * 处理上、下按钮
 * @param hasPrev 是否有上一页
 * @param hasNext 是否有下一页
 */
open fun handlePrevNext(hasPrev: Boolean, hasNext: Boolean) {}

IDateRange 接口说明

日期范围选择RangeCalendarView,如果自定义headerView实现该接口,可更新headerView日期范围,可参考DefaultRangeHeaderView类

class DefaultRangeHeaderView(
        context: Context
) : DefaultHeaderView(context), IDateRange {

    private lateinit var dateRangeLabel: TextView

    override fun dateRange(startDate: DateInfo?, endDate: DateInfo?) {
        if (startDate == null && endDate == null) {
            dateRangeLabel.text = ""
        } else if (startDate != null && endDate != null) {
            dateRangeLabel.text = "${startDate.format()} -- ${endDate.format()}"
        } else if (startDate != null) {
            dateRangeLabel.text = startDate.format()
        }
    }

    override fun getLayoutId(): Int {
        return R.layout.default_range_header_view
    }

    override fun init() {
        super.init()
        dateRangeLabel = findViewById(R.id.date_range_label)
   }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容