Android 自定义日历控件

2018-05-10  本文已影响0人  木小伍
废话不多说,先直接上最终的效果图(完整代码链接在底部)
日历.png

实现思路

首先,我们将效果图实现的过程,拆分:
1,将整个布局进行拆分,分别实现
2,用系统calendar类实现数据填充
3,附属数据的填充(比如日消费什么的)

第一步,界面铺设

瞄一眼,就很容易得出该日历由三个部分组成,
a.月份标题
b.星期数
c.日历数据
以下是我的实现布局

<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
        android:layout_height="40dp">

        <ImageView
            android:id="@+id/btn_calendar_pre"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:src="@mipmap/arrow_pre" />

        <TextView
            android:id="@+id/tv_calendar_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="5月18"
            android:textColor="#000000"
            android:textSize="20sp" />

        <ImageView
            android:id="@+id/btn_calendar_next"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:src="@mipmap/arrow_next" />

    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="日"
            android:textColor="#000"
            android:textSize="16sp" />

      //..........

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recy_calendar"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

效果如下,主要功能在日历数据的展示上面,我采用的是recycleview布局


布局.png

第二步,日历数据的填充

 private void initData(Context context) {
        dateList.clear();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy - MM");
        //年月--设置标题栏的数据
        String dateTitle = sdf.format(mCalendar.getTime());
        tvDateTitle.setText(dateTitle);

        //表格中的数据
        Calendar calendar = (Calendar) mCalendar.clone();
        calendar.set(Calendar.DAY_OF_MONTH, 1); //设置时间到当前月份的第一天

        //1---代表周日  2---代表周一
        int firstDay = calendar.get(Calendar.DAY_OF_WEEK);//获取日期的偏移量

        int preDays = firstDay - 1; //因为角标是从0开始的
        //仅仅美观操作,下面代码可加可不加 效果参见pc系统的日历月份调至  2018-4
        preDays = preDays == 0 ? 7 : preDays; //为了保证第一行一定是 上个月+这个月(可能没有) 的数据 ,
        //最后一行一定是 这个月(可能没有)+下个月 的数据
        calendar.add(Calendar.DAY_OF_MONTH, -preDays);//将偏移量移至上个月,把上个月的几天添加到本月的日历中

        int maxDays = 6 * 7;//直接写死,6行7列,至于为什么,请参考pc右下角日历
        ClendarInfo clendarInfo;
        Date time = null;
        sdf = new SimpleDateFormat("yyyy-MM-dd");
        boolean needDoThing = dataMap.size() > 0;  //表示当月有数据
        for (int i = 0; i < maxDays; i++) {
            time = calendar.getTime();
            clendarInfo = new ClendarInfo();

//-------第三步----------添加附属数据开始----------------------------
            String key = sdf.format(new Date(time.getYear(), time.getMonth() + 1, time.getDate()));
            if (needDoThing && dataMap.containsKey(key)) { //将本月需要做的事添加到集合中,而且的当前月份
                String thing = dataMap.get(key);
                if (!TextUtils.isEmpty(thing))
                    clendarInfo.setDoThing(thing);
            }
//-------第三步----------添加附属数据结束----------------------------
            clendarInfo.setDate(time);
            dateList.add(clendarInfo);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        //  Log.i("TAG", "dataMap=" + dataMap.toString());
        //将日历数据填充到recycleview中
        if (adapter == null) {
            adapter = new DateAdapter(context, R.layout.item_calendar_layout, dateList);
            adapter.setOnItemClickListener(this);
            recyclerView.setAdapter(adapter);

        } else {
            adapter.notifyDataSetChanged();
        }
    }

第二步中,主要的要注意的地方是:
a.星期天的角标是0,
b.一月份的角标是0
c.Calendar.add(Calendar.DAY_OF_MONTH, 1);可以理解为在月份中,参数 1 表示日期往后挪一天,-1 表示往前面挪一天。
Calendar.add(Calendar.MONTH, +1); //当前月加1,即下个月
Calendar.add(Calendar.MONTH, -1);//当前月减1,即上个月
以上方法就是生成日历数据的核心代码了。代码的注释也写的很详细,如果还不清楚,可在文末将完整代码复制下来,或者在文本末,下载该博客的demo

第三步,添加附属数据

实现的主要方法,就是步骤二中的代码中注释掉的部分了。
至于,不是当前月的日期显示灰色,当天日期标红,当前月黑色显示,就是在recycleview的adapter中实现了,这些都很简单,就写出来了。

      Map<String, String> dataMap = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 1)), "吃饭");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 11)), "睡觉");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 16)), "打豆豆");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 21)), "继续睡觉");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 9)), "来啊,继续浪");
        dataMap.put(sdf.format(new Date(2018-1900, 5, 30)), "打豆豆");
        
        clendarView.setDataMap(dataMap);

上面这段代码是从activity中传入的附属数据,具体情况,要按照需求来决定,仅仅作为参考。最后附上demo地址

上一篇下一篇

猜你喜欢

热点阅读