您的位置:首页 > 移动开发 > Android开发

Android带日程安排的自定义日历控件

2015-10-27 14:46 501 查看
前言:

本文实现的是,自定义的日历控件,可以添加日程安排。

本篇是基于网上源码做的相应修改,本文只列出修改的内容,需要看源码博文的请到:
http://blog.csdn.net/h7870181/article/details/8960478
一、效果展示



二、日历控件的修改

1、星期显示中文

此处,原控件里显示的是英文,本处改成中文,这个改动十分简单,只要能看懂代码的人,都会修改,我就在此处顺便练习了一下枚举类型的使用。

该处修改,是在CalendarView的一个内部类Surface里进行的,该类主要的目的是初始化一些参数设置,比如画笔颜色、日期框宽度、日期数组等等。以下是修改的部分代码:

<span style="font-size:12px;">public String[] weekText = {DateEnum.SUN.getValue(), DateEnum.MON.getValue(), DateEnum.TUE.getValue(),
DateEnum.WED.getValue(), DateEnum.THU.getValue(), DateEnum.FRI.getValue(), DateEnum.SAT.getValue()};</span>


其中,DateEnum是我定义的周枚举类型,此处比较简单,不再多叙述,详情可参考源码。

2、改变周末的显示颜色

可以看到截图中,周六和周日字体颜色显示为粉色,这里也比较简单,在源码中找到绘制这些字的位置,然后加一个判断是否为周末的控制语句即可完成。

首先,绘制是在onDraw中进行的,

for (int i = 0; i < 42; i++) {
int color = surface.textColor;
if (isWeekEnd(i)) {
color = surface.weekDayColor;
}
if (isLastMonth(i)) {
color = surface.borderColor;
} else if (isNextMonth(i)) {
color = surface.borderColor;
}
if (todayIndex != -1 && i == todayIndex) {
color = surface.todayNumberColor;
}
drawCellText(canvas, i, date[i] + "", color);
}


在代码中,我们可以看出,绘制原理其实就是绘制42个格子,并在格子里面画上相应的日期,在一些特殊情况下,改变字体的颜色,比如当日显示为红色,还有我加入的周末显示为粉色。判断是否是周末,我用了一个比较笨的方式,将42个格子中,所有周末的下标记录在同一个数组里面,再进行判断,

<span style="font-size:12px;">private boolean isWeekEnd(int date) {
//6*7的方格中,以下位置代表的是周末
int[] weekEnd = new int[]{6, 7, 13, 14, 20, 21, 27, 28, 34, 35};
boolean isWeekEnd = false;
int i = 0;
while (i < weekEnd.length) {
if (date == weekEnd[i]) {
isWeekEnd = true;
break;
}
i++;
}
return isWeekEnd;
}</span>

这里还要考虑到一个问题,就是代表上一个月和下一个月日期,即截图中灰色日期部分,是不能够显示为粉色的,所以if (isWeekEnd(i))的判断,一定要在if (isLastMonth(i))这个判断的前面。

3、日程红点的加入

首先需要在CalendarView中,定义一个ArrayList,用于记录需要绘制点的下标

<span style="font-size:12px;">private List<Integer> spotList = new ArrayList<Integer>();//需要加点的位置数组\</span>

其次在onDraw方法中,添加一个绘制圆点方法的调用

<span style="font-size:12px;">drawSpot(canvas, spotList);</span>

然后我们来看一下这个方法里面做了什么,

<span style="font-size:12px;">private void drawSpot(Canvas canvas, List<Integer> spotList) {
for (int i : spotList) {    //循环遍历spotList画点
drawSpotDetail(canvas, i);
}
}</span>

循环遍历,画点方法:

<span style="font-size:12px;">private void drawSpotDetail(Canvas canvas, int index) {
int x = getXByIndex(index);
int y = getYByIndex(index);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(15);
float cellY = surface.monthHeight + surface.weekHeight + (y - 1)
* surface.cellHeight + surface.cellHeight * 1 / 4f;
float cellX = (surface.cellWidth * (x - 1))
+ (surface.cellWidth)
/ 2f;
canvas.drawPoint(cellX, cellY, paint);
}</span>

这方法是首先根据索引计算点的位置,然后画点。

接下来就是从外部把需要画点的list传入到控件中,然后再调用一次invalidate();方法,就可以重新执行onDraw方法,实现点的重绘,此处提供了对外开放的方法

<span style="font-size:12px;">public void change(List<Integer> spotList) {
this.spotList.clear();
this.spotList.addAll(spotList);
invalidate();
}</span>

对于日历控件的修改,大致上就是这些,当然还有一些小的修改就不足为提了,下面介绍添加日程的部分。

二、在日历控件下面,添加日程模块

这个功能我是用ExpandableListView来实现的,将ExpandableListView放到日历控件的下面,再为ExpandableListView和CalendarView添加相应的交互即可。

1、布局文件

<span style="font-size:12px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<RelativeLayout
android:id="@+id/layout_calendar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="visible"
android:background="@color/calendar_top_bg">

<TextView
android:id="@+id/calendarCenter"
style="@style/main_bar_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="8dp" />

<ImageButton
android:id="@+id/calendarLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="@null"
android:contentDescription="@null"
android:padding="8dp"
android:src="@drawable/calendar_month_left" />

<ImageButton
android:id="@+id/calendarRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@null"
android:contentDescription="@null"
android:padding="8dp"
android:src="@drawable/calendar_month_right" />

<com.example.calendarviewdemo.CalendarView
android:id="@+id/calendar"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_below="@+id/calendarCenter" />

</RelativeLayout>

<ExpandableListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:childDivider="@android:color/transparent"
android:background="@color/white"
android:groupIndicator="@null"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout></span>

ExpandableListView的学习资料也很多,以下就简述重点及遇到的问题了,有兴趣的可以下载源码查看全部代码。

2、ExpandableListView数据没有更改之前,setSelectedGroup()方法调用效果一切正常;而填充数据更改notifyDataSetChanged之后,同样的代码片段却莫名其妙无效了,该问题我用以下方法得以解决,

<span style="font-size:12px;">mListView.post(new Runnable() {            </span>
<span style="font-size:12px;">            @Override
public void run() { //因此此处放在线程里
mListView.setSelectedGroup(calendar.getNowDate() - 1);  //设置初始listview的显示位置,为本日
}
});</span>

3、CalendarView的点击事件

<span style="font-size:12px;">calendar.setOnItemClickListener(new OnItemClickListener() {

@Override
public void OnItemClick(java.util.Date selectedStartDate,
java.util.Date selectedEndDate, java.util.Date downDate) {
setHeadDate(format.format(downDate));   //头上的日期显示更换
String[] ya = getStrings(format.format(downDate));  //获取按下的日期,目的是获取“日”,与mListView的下标对比,得到要显示的位置
String[] nowDate = getStrings(calendar.getYearAndmonthAndDate());
if(ya[1].equals(nowDate[1])){   //用于限制本页显示灰色的上一月和下一月,点击后不执行以下代码
mListView.setSelectedGroup(Integer.valueOf(ya[2]) - 1); //日期比下标大1,因此这里减1,可定位到正确位置
}
}
});</span>

这里要实现两个目的,第一点击后标题上的日期显示更改,第二下面的ExpandableListView显示的Group的Item也要做相应的修改,注意这里有一个问题,为灰色的日期也是可以设置点击时间,但是显然我们不希望点了这些灰色日期后,ExpandableListView位置发生变化,因此做了一个是否是本月的判断,只有在本月,点了以后ExpandableListView的位置才能发生变化。

3、点击ExpandableListView的child的最后一项时,(最后一项显示的内容为“新建日程”),调用CalendarView绘制红点的方法

<span style="font-size:12px;">mListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int groupPosition, int childPosition, long l) {
if(child.get(groupPosition).size() == childPosition + 1){
spotList.add(Integer.valueOf(group.get(groupPosition)) - 1 + calendar.getcurStartIndex());
calendar.change(spotList);
Toast.makeText(MainActivity.this, "添加了一个日程" , Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "hah" + childPosition , Toast.LENGTH_SHORT).show();
}
return false;
}
});</span>


注意这里,ExpandableListView要使用setOnChildClickListener这个监听时,在其adapter中重写的isChildSelectable,返回值必须为true,否则监听无效。

<span style="font-size:12px;">@Override
public boolean isChildSelectable(int i, int i2) {
return true;
}</span>

4.ExpandableListView的一些设置

去掉默认Group上面的箭头
android:groupIndicator="@null"

去掉child里面的分割线
android:childDivider="@android:color/transparent"

设置不可闭合
在adapter中,view.setClickable(true);

设置默认展开所有group
for(int i = 0; i < group.size(); i++){
mListView.expandGroup(i);

}

终于写好了~ 内容不是什么高大尚的东西,希望对新手有些帮助!

欢迎提出宝贵意见!

源码下载:源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: