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

Posted 我爱烤冷面

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android带日程安排的自定义日历控件相关的知识,希望对你有一定的参考价值。

前言:

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

      本篇是基于网上源码做的相应修改,本文只列出修改的内容,需要看源码博文的请到:

                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);
           

 

 

 

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

         欢迎提出宝贵意见!

        

 

         源码下载:源码下载





以上是关于Android带日程安排的自定义日历控件的主要内容,如果未能解决你的问题,请参考以下文章

winform日历控件

Android自定义View(CustomCalendar-定制日历控件)

我生成了一个换行的自定义Label控件,如何取得该行数啊??

如何设计WinForm中DataGridView控件的自定义按钮列

Android从零单排系列十一《Android视图控件——日历日期时间选择控件》

freeCalendar-自定义日历控件