之前碰到项目一个地方要添加日历,通过点击最近12个月的某一天返回当天的日期功能,本来想直接从网上拖个demo下来用进去,但是看了看需求以及实现方式,觉得改动有点大,所以就决定还是自己去写个日历控件,同时也算是复习下calendar类相关信息吧
其中具体实现效果为下图:其中左侧选择月份的可以上下滑动选择最近12个月,右侧点击日历后就返回当前点击的yyyyMMdd给调用类设置的监听方法
之前看网上demo自定义日历采用的一般是在ondraw中绘制一个一个小格子,然后计算好后拼凑一下,这个是个好方法,会让界面很容易对齐,美观,并且可以实现小格子的很多效果,
由于需求不同,需要加点滑动的东西,想了下还是直接利用系统提供的组建搭建一起会更方便些,所以最后决定采用了listview + gridview的技术实现
代码比较简单,主要涉及的知识为calendar类的api调用,listview与gridview的事件监听,回调函数的编写,以及界面上的一些实现
其中
1、calendar主要代码为:
final Calendar cal = Calendar.getInstance();//获取日历实例
Date nowDate = new Date();//获取当前date
cal.setTime(nowDate);
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) - 11);
for (int i = 0; i < 12; i++) {//为月份添加数据
lvList.add(dateFormat.format(cal.getTime()));
cal.add(Calendar.MONTH, 1);
}
choiceMonth = lvList.get(lvList.size() - 1);//设置默认选中的年月
cal.setTime(nowDate);//cal设置为当天的
cal.set(Calendar.DATE, 1);//cal设置当前day为当前月第一天
int tempSum = countNeedHowMuchEmpety(cal);//获取当前月第一天为星期几
int dayNumInMonth = getDayNumInMonth(cal);//获取当前月有多少天
setGvListData(tempSum, dayNumInMonth);//设置gridview的数据
2、接着是事件的监听传递:
lv.setOnItemClickListener(new OnItemClickListener() {//listview的监听事件,主要是通知gridview数据变化
@Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long arg3) {
if (position == lvAdapter.getSelectPosition()) {
return;
} else {
lvAdapter.setSelectPosition(position);
}
String num = (String) adapterView.getAdapter()
.getItem(position);
try {
cal.setTime(dateFormat.parse(num));
cal.set(Calendar.DATE, 1);
choiceMonth = num;
setGvListData(countNeedHowMuchEmpety(cal),
getDayNumInMonth(cal));
gridViewAdapter.notifyDataSetChanged();
setListViewHeight(gv, lv);
} catch (ParseException e) {
e.printStackTrace();
}
lv.setSelection(position);
}
});
gv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View arg1,
int position, long arg3) {
String choiceDay = (String) adapterView.getAdapter().getItem(
position);
if (!"".equals(choiceDay)) {
if (Integer.parseInt(choiceDay) < 10) {
choiceDay = "0" + choiceDay;
}
String date = choiceMonth + choiceDay;
if (callBack != null) {//调用回调函数回调数据
callBack.onDaySelectListener(date);
}
}
}
});
3、回调函数的设置
/**
* 自定义监听接口
* @author Administrator
*
*/
public interface OnDaySelectListener {
void onDaySelectListener(String date);
}
/**
* 自定义监听接口设置对象
* @param o
*/
public void setOnDaySelectListener(OnDaySelectListener o) {
callBack = o;
}
4、界面上的实现
这个比较麻烦点,这里面需要实现gridview的边框功能,需要设置listview的高度,
其中gridview的边框功能之前我有实现过一个重新自定义的gridview,然后在重写dispathdraw()方法当中通过gechildAt(position)(ps:具体方法名忘记了,反正就是获取子view过来)获取到子view,然后计算子view在那一列,通过drawline的方法在四周增加上对应的线;但是这里的话可以采用在adapter的view中去做手脚,直接在布局中画下划线和右侧的线就行了,具体布局代码为:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_calendar_day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dip"
android:layout_marginTop="10dip"
android:gravity="center"
android:textSize="15sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#7d7d7d" />
</LinearLayout>
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="#7d7d7d" />
</LinearLayout>
这样就能模拟出一个开放型的边框了,但是大家会发现,gridview中的item总是比gridview的宽,高小一点点,而且无论怎么设置都没办法完全布满gridview,这个原因实际上是girdview的listSelector在作怪,它自己会带有一点点的距离的,所以在gridview中将 android:listSelector="@null"加上就可以布满整个gridview的大小啦~
接着就是根据gridview的高度去设置listview的高度:
/**
* 根据gridview所占有的高度设置listview的高度
* @param gv
* @param lv
*/
private void setListViewHeight(GridView gv, ListView lv) {
int totalHeight = 0;
ListAdapter adapter = gv.getAdapter();
for (int i = 0, len = adapter.getCount(); i < len; i++) {
View listItem = adapter.getView(i, null, gv);
listItem.measure(0, 0);
totalHeight = Math.max(totalHeight, listItem.getMeasuredHeight());
}
int row = adapter.getCount() % 7 == 0 ? adapter.getCount() / 7
: adapter.getCount() / 7 + 1;
ViewGroup.LayoutParams lvparams = lv.getLayoutParams();
lvparams.height = row * totalHeight + gv.getPaddingTop()
+ gv.getPaddingBottom();
lv.setLayoutParams(lvparams);
}
这样整个功能就已经可以出来了,
最后实际上大多还是对gridview的使用吧,截图中的日历弹出是在一个popupwindow中,但给出的源码里就直接展示吧,嘿嘿;因为时间仓促,所以里面可能会有些不合理或者影响性能的地方,还请广大博友指明,共勉。
转载请注明出处iamwsbear@gmail.com
ps:因为之前上传折线图源码就只是上传了折线图的view和需要的资源文件,里面实际含有了demo测试数据,导入应该就能看到效果了,但是有的朋友还是希望能够上传一个完整的工程,所以这次就放一个完整的吧
0分源码地址:点击进入下载页