Android自定义日历控件

最近准备开始学习自定义View了,之前项目上也说需要一个日历控件,当时就在网上找了一个,现在想自己做一个自定义控件,基本的实现思路也是在慕课网上面学习的,先上图吧:
cmd-markdown-logo

布局的组成

目前日历实现了两个功能,第一个就是可以进行前后月份的切换,第二就是点击某一天,返回该天的日期
我们先来看一下是怎么实现的吧,首先说一下布局:
1、头部展示当前日期的那一行是一个LinearLayout控件,里面包含了两个ImageView用于切换月份,还包含了一个TextView显示当前日期
2、中间星期的展示部分是一个LinearLayout控件,里面包含了七个TextView用于显示一周中每一天
3、具体日期的显示部分则是一个GridView

功能代码的实现

显示日历

首先我们要获取当前月的Calendar实例:

1
Calendar mCalendar = Calendar.getInstance();//这是一个全局变量

接下来我们在方法renderCalendar()中具体的去实现获取当前月的每一天的Date数据,我们看一下整体的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//获取当前月的数据
private void renderCalendar(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
mTxtDate.setText(sdf.format(mCalendar.getTime()));//格式化当前的日期并显示
dates = new ArrayList<>();//创建一个Date的ArrayList
Calendar calendar = (Calendar) mCalendar.clone();//将全局变量mCalendar克隆过来
calendar.set(Calendar.DAY_OF_MONTH, 1);//设置当前的时间为当月的第一天
int firstDayWeek = calendar.get(Calendar.DAY_OF_WEEK)-1;//获取当月第一天是星期几
if(firstDayWeek == 0){
firstDayWeek = 7;//因为Calendar中每周是从周日开始的,所以当计算结果为0时,证明该天是周日
}
int dayCountInCurrentMonth = getCurrentMonthDay(calendar);//获取当前月的总天数
calendar.add(Calendar.DAY_OF_MONTH, -(dayCountInCurrentMonth-1));//讲日历中的第一天移动到正确的星期
int allDaysInView = firstDayWeek + dayCountInCurrentMonth - 1;//获取日历中应该显示的item数量
for(int i=0; i < allDaysInView; i++){
if(i<firstDayWeek-1){
dates.add(null);//当这个item在当前月第一天之前时,添加null
continue;
}
dates.add(calendar.getTime());//将Date加入到dates中
calendar.add(Calendar.DAY_OF_MONTH, 1);//日期向后顺延一天
}
mAdapter = new RuiCalendarAdapter(getContext(), dates);//通过Adapter将日期展示出来
mGridView.setAdapter(mAdapter);
}
//获取当前月的总天数
public static int getCurrentMonthDay(Calendar calendar) {
calendar.set(Calendar.DATE, 1);
calendar.roll(Calendar.DATE, -1);
int maxDate = calendar.get(Calendar.DATE);
return maxDate;
}

进行前后两个月的切换

向前切换月份

1
2
mCalendar.add(Calendar.MONTH, -1);//前一个月
renderCalendar();//重新获取数据显示

向前切换月份

1
2
mCalendar.add(Calendar.MONTH, 1);//后一个月
renderCalendar();//重新获取数据显示

点击返回选择的时间

点击时间的实现需要借助接口回调,首先我们要在RuiCalendar这个类中自定义一个接口OnItemClickListener并且声明

1
2
3
4
5
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener{
void onItemClick(Date date);
}

接下来我们要利用实现GridView的Item点击事件去监听我们自定义的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mGridView.setOnItemClickListener(this);
// 设置日历的点击事件
public void setOnItemClickListener(OnItemClickListener listener){
mOnItemClickListener = listener;
}
//gridview的点击事件
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if(mOnItemClickListener != null){
mOnItemClickListener.onItemClick(dates.get(i));
}
int childCount = mGridView.getChildCount();
for(int n=0; n< childCount; n++){
mGridView.getChildAt(n).setBackgroundColor(Color.parseColor("#00E6E4E5"));
}
mGridView.getChildAt(i).setBackgroundColor(Color.parseColor("#FFE6E4E5"));
}

这样我们的接口回调就已经写好了,剩下来要做的就是要去MainActivity中调用这个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
protected void onCreate(Bundle savedInstanceState) {
、、、
mRuiCalendar.setOnItemClickListener(this);
}
//日历点击事件的回调
@Override
public void onItemClick(Date date) {
Log.i("=========", date.toString());
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("您选择的时间是:")
.append(date.getYear()+1900)
.append("年")
.append(date.getMonth()+1)
.append("月")
.append(date.getDate())
.append("日 ").append(new SimpleDateFormat("EEEE").format(date));
mTextView.setText(stringBuilder.toString());
}

使用手册

该项目已经在github上面发布了,如果要调用的话需要在项目中添加下面几句代码
project gradle.build中添加

1
2
3
4
5
6
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}

app gradle.build中添加

1
2
3
dependencies {
compile 'com.github.hurui1990:RuiCalendar:v1.0.2'
}

具体的调用代码如下:
布局文件中

1
2
3
4
5
<com.hurui.customcalendar.RuiCalendar
android:id="@+id/ruicalendar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.hurui.customcalendar.RuiCalendar>

MainActivity中

1
2
RuiCalendar mRuiCalendar = (RuiCalendar) findViewById(R.id.ruicalendar);//获取控件
mRuiCalendar.setOnItemClickListener(this);//设置监听

项目Github地址

上述就是整个自定义日历控件的实现过程,功能还是很简单的,以后有时间的话,会在此基础上添加一些更加实用的功能,欢迎大家指正不足之处!