android自定义控件---android日历

本文介绍了一种自定义日历控件的实现方法,利用ListView和GridView搭建,支持滑动选择最近12个月并点击返回日期的功能。文章详细解释了Calendar类的应用、事件监听的设置及回调函数的编写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         之前碰到项目一个地方要添加日历,通过点击最近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分源码地址:点击进入下载页





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值