美文网首页
Android 自定义日历控件

Android 自定义日历控件

作者: 木小伍 | 来源:发表于2018-05-10 15:22 被阅读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地址

    相关文章

      网友评论

          本文标题:Android 自定义日历控件

          本文链接:https://www.haomeiwen.com/subject/fcizrftx.html