Skip to content

v2.0.1文档

zfman edited this page Aug 3, 2018 · 1 revision

v2.0.1文档

本文中的功能介绍、控件用法均针对v2.0.0以及v2.0.1,它并不是最新的,你可以在 ChangeLog 查看本控件的开发进展,作者联系方式1193600556@qq.com

TimetableView是一款开源的Android课程表控件。

  • 支持xml设置属性、数据源
  • 提供了默认的周次选择栏(超级课程表效果),支持自定义
  • 提供了默认的日期栏,支持自定义
  • 多项侧边栏配置项,可设置时间的显示与否,支持自定义
  • 多项课程项配置项,可拦截、可修改弧度、可设置非本周是否显示
  • 课程颜色管理:使用颜色池来管理颜色,操作灵活
  • 高效灵活:切换周次高效率、一个样式文件实现了多种课程项样式效果
  • 可替换滚动布局:不将该控件绑死在固有的ScrollView中
  • 无界面操作:你可以使用工具类对课程进行模拟分配颜色、获取有课的课程等

11

准备数据源

在开始使用控件之前,你需要准备好数据源,数据可以从网上获取或者使用本地数据,为了方便演示,使用本地的JSON字符串,然后再将其解析为需要的格式

基础功能

本节你将掌握如何使用本控件搭建自己的课表界面。这里使用的版本为2.0.1

添加依赖

Gradle

compile 'com.zhuangfei:TimetableView:2.0.1'

Maven

<dependency>
  <groupId>com.zhuangfei</groupId>
  <artifactId>TimetableView</artifactId>
  <version>2.0.1</version>
  <type>pom</type>
</dependency>

添加控件

该控件包含的基础组件有日期栏、侧边栏、课表视图,在布局文件中加入如下代码后会包含这三个基础组件

    <com.zhuangfei.timetable.TimetableView
        android:id="@+id/id_timetableView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.zhuangfei.timetable.TimetableView>

配置属性

使用如下方式获取到控件

   TimetableView mTimetableView = findViewById(R.id.id_timetableView);    

属性的设置分为两类:与课程项构建有关的、与全局有关的,前者的配置在ScheduleManager对象中,后者的配置在TimetableView中,所有配置信息需要在showView()调用前完成,否则无效

以下代码用来监听课程项点击事件:

mTimetableView.getScheduleManager()
                .setOnItemClickListener(new ISchedule.OnItemClickListener() {
                    @Override
                    public void onItemClick(View v, List<Schedule> scheduleList) {
                        display(scheduleList);
                    }
                });       

然后设置它的一些全局属性,最后调用showView()用来创建和显示课表视图,代码如下:

mTimetableView.setSource(mySubjects)
                .setCurWeek(1)
                .setCurTerm("大三下学期")
                .showView();    

至此,课表已经可以显示在视图上了,你可能会问:设置数据源时mySubjects是什么?不要着急,继续看...

数据源设置

数据源的设置方式有两种,以下分别来介绍:

方法1:使用指定的格式List<Schedule>,Schedule是控件提供的课程实体类,你可以将自己的数据封装为指定格式,然后进行如下配置即可

 mTimetableView.setData(scheduleList)
                .setCurWeek(1)
                .setCurTerm("大三下学期")
                .showView();

方法2:方法1在很多场景下都满足不了需求,往往需要定义自己的课程实体类,你可以跟随以下几个步骤来使用它

  • 创建自定义的实体类并实现ScheduleEnable接口
public class MySubject implements ScheduleEnable {
  //省略属性、setter、getter、构造函数

   @Override
  public Schedule getSchedule() {
      Schedule schedule=new Schedule();
      schedule.setDay(getDay());
      schedule.setName(getName());
      schedule.setRoom(getRoom());
      schedule.setStart(getStart());
      schedule.setStep(getStep());
      schedule.setTeacher(getTeacher());
      schedule.setWeekList(getWeekList());
      schedule.setColorRandom(2);
      return schedule;
   }
}
  • 使用setSource()设置
//模拟获取课程数据:自定义格式
List<MySubject> mySubjects = SubjectRepertory.loadDefaultSubjects();

//设置数据源并显示
mTimetableView.setSource(mySubjects)
                .setCurWeek(1)
                .setCurTerm("大三下学期")
                .showView();    

可见,上述那个例子使用的是方法2,我个人也建议使用方法2:比较灵活,可根据具体情况选择。简单几步,课表界面就可以显示出来了,是不是有点小激动呀。

删除课程

/**
     * 删除课程
     * 内部使用集合维护课程数据,操作集合的方法来操作它即可
     * 最后更新一下视图(全局更新)
     */
    protected void deleteSubject() {
        int size = mTimetableView.getDataSource().size();
        int pos = (int) (Math.random() * size);
        if (size > 0) {
            mTimetableView.getDataSource().remove(pos);
            mTimetableView.updateView();
        }
    }

添加课程

    /**
     * 添加课程
     * 内部使用集合维护课程数据,操作集合的方法来操作它即可
     * 最后更新一下视图(全局更新)
     */
    protected void addSubject() {
        int size = mTimetableView.getDataSource().size();
        if (size > 0) {
            Schedule schedule = mTimetableView.getDataSource().get(0);
            mTimetableView.getDataSource().add(schedule);
            mTimetableView.updateView();
        }
    }

周次选择栏

周次选择栏WeekView是控件实现的一个默认的周次选择控件,你可以使用它快速的拥有周次选择功能,TimetableView是没有周次选择功能的,所以需要两者配合使用。 本节你将掌握使用zfman/TimetableView添加一个周次选择栏

默认的周次选择栏

1.添加控件

在布局文件中放一个TimetableView,然后在TimetableView的上边放一个WeekView

	<com.zhuangfei.timetable.view.WeekView
        android:id="@+id/id_weekview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <com.zhuangfei.timetable.TimetableView
        android:id="@+id/id_timetableView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.zhuangfei.timetable.TimetableView>

2.获取控件

TimetableView mTimetableView;
WeekView weekView;
//获取控件
mTimetableView = findViewById(R.id.id_timetableView);
weekView=findViewById(R.id.id_weekview);

3.设置WeekView

	    //设置周次选择属性
        weekView.setSource(mySubjects)
                .setCurWeek(1)
                .setOnWeekItemClickedListener(new IWeekView.OnWeekItemClickedListener() {
                    @Override
                    public void onWeekClicked(int curWeek) {
                        mTimetableView.changeWeekOnly(curWeek);
                    }
                })
                .setOnWeekLeftClickedListener(new IWeekView.OnWeekLeftClickedListener() {
                    @Override
                    public void onWeekLeftClicked() {
                        Log.d(TAG, "onWeekLeftClicked: ");
                        onWeekLeftLayoutClicked();
                    }
                })
                .showView();

4.设置TimetableView

mTimetableView.setSource(mySubjects)
                .setCurWeek(1)
                .setCurTerm("大三下学期")
                .setOnWeekChangedListener(new ISchedule.OnWeekChangedListener() {
                    @Override
                    public void onWeekChanged(int curWeek) {
                        int size = mTimetableView.getDataSource().size();
                        titleTextView.setText("第" + curWeek + "周,共" + size + "门课");
                    }
                })
                .showView();

5.更新高亮日期

由于在onCreate中设置了WeekView,所以默认的在WeekView初始化时会计算当前日期,如果程序在后台时间太长(超一天),那么进入页面时会发现日期不正确,所以可以在Activity的onStart生命周期方法中再次计算日期,设置高亮

@Override
    protected void onStart() {
        super.onStart();
        //更新一下,防止因程序在后台时间过长(超过一天)而导致的高亮不准确问题
        //第一次调用时会出异常
        try{
            mTimetableView.getOnDateBuildListener().onHighLight();
        }catch (Exception e){

        }

    }

自定义周次选择栏

这个没什么可说的,你只需要任意的定制即可,因为它与TimetableView是没有任何关联的,有问题可以参考WeekView的实现

自定义属性

本控件不仅支持在代码中对属性进行设置,部分属性和监听还支持在布局文件xml中配置,一起来看看吧~

属性列表

以下罗列的属性或监听可以在xml中配置

<!--Some Attr with TimetableView-->
    <declare-styleable name="TimetableView">

        <!--当前周-->
        <attr name="cur_week" format="integer"/>

        <!--当前学期-->
        <attr name="cur_term" format="string"/>

        <!--
            指定一个方法名,该方法符合以下要求:
            1.返回值为一个集合
            2.集合中的每个对象都实现了ScheduleEnable接口
            -->
        <attr name="source" format="string"/>

        <!--
            指定一个方法名,该方法符合以下要求:
            1.返回值为List<Schedule>
            -->
        <attr name="data" format="string"/>

        <!--课程项的上边距-->
        <attr name="mar_top" format="dimension"/>

        <!--左边距-->
        <attr name="mar_left" format="dimension"/>

        <!--课程项的高度-->
        <attr name="item_height" format="dimension"/>

        <!--本周课程的圆角弧度-->
        <attr name="thisweek_corner" format="dimension"/>

        <!--非本周课程的圆角弧度-->
        <attr name="nonweek_corner" format="dimension"/>

        <!--侧边栏的最大项-->
        <attr name="max_slide_item" format="integer"/>

        <!--是否显示非本周课程-->
        <attr name="show_notcurweek" format="boolean"/>
        
        <attr name="onWeekChanged" format="string"/>
        
        <attr name="onItemClicked" format="string"/>
    </declare-styleable>

属性设置

在根节点添加一个名为app的命名空间

xmlns:app="http://schemas.android.com/apk/res-auto"

直接在xml中对属性设置

<com.zhuangfei.timetable.TimetableView
        android:id="@+id/id_timetableView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:cur_week="3"
        app:cur_term="大三上学期"
        app:show_notcurweek="false"
        app:source="getSource"
        app:max_slide_item="10"
        app:onWeekChanged="onWeekChanged"
        app:onItemClicked="onItemClicked"/>

显示视图

由于大部分的属性都在xml中配置过了,所以在Activity中只负责显示即可

mTimetableView.showView();

那么数据源从哪来呢?注意到xml中指定了app:source="getSource",所以在Activity中需要有一个List<MySubject> getSource()方法,控件会自动的调用该函数对数据源进行设置

/**
     * 使用自己的格式设置数据源,方法名任意,但必须和xml中设置的一致
     * @return
     */
    public List<MySubject> getSource(){
        return SubjectRepertory.loadDefaultSubjects();
    }

同理,可以设置课程项点击监听

/**
 * 设置点击监听
  * @return
  */
    public void onItemClicked(View v,ArrayList<Schedule> scheduleList){
        Log.d(TAG, "onItemClicked: "+scheduleList.size());
        display(scheduleList);
    }

同理,可以设置周次改变监听

/**
     * 监听周次改变的方法,方法名任意,但必须和xml中设置的一致
     * 参数必须与示例一致
     * @return
     */
    public void onWeekChanged(int curWeek){
        Log.d(TAG, "onWeekChanged: "+curWeek);
        if(mTimetableView!=null){
            int size = mTimetableView.getDataSource().size();
            titleTextView.setText("第" + curWeek + "周,共" + size + "门课");
        }
    }

日期栏

本节主要演示如何对日期栏的属性设置以及自定义日期栏的步骤

隐藏日期栏

/**
     * 隐藏日期栏
     */
    protected void hideDateView(){
        mTimetableView.hideDateView();
    }

显示日期栏

/**
     * 显示日期栏
     */
    protected void showDateView(){
        mTimetableView.showDateView();
    }

自定义日期栏

Step1:自定义布局

需要定义两个布局,第一个item_custom_dateview_first.xml定义的月份的样式

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_week_month"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical|center_horizontal"
    android:textSize="12sp"
    android:textStyle="bold" />

第二个item_custom_dateview.xml定义的是星期一至星期日的每项的样式

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_week_layout"
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:gravity="center_horizontal|center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@+id/id_week_day"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:textStyle="bold" />
</LinearLayout>

Step2:自定义实现类 定义了类CustomDateAdapter并实现了ISchedule.OnDateBuildListener接口,实现三个方法:

  • getDateViews(LayoutInflater mInflate,float perWidth,int height) 获取View数组,perWidth是每个单位的宽度,月份占1个单位,其余为1.5个单位
  • onHighLight() 设置高亮时回调
  • onUpdateDate() 更新日期时回调

以下代码有一些长,请细细品味~~

/**
     * 大部分代码copy的OnDateBuildAapter
     * 你可以决定是否使用该方式,如果不愿使用该方式,
     * 可以隐藏日期栏,自行实现即可
     * @see com.zhuangfei.timetable.listener.OnDateBuildAapter
     */
    class CustomDateAdapter implements ISchedule.OnDateBuildListener {

        //第一个:月份,之后7个表示周一至周日
        LinearLayout[] layouts=new LinearLayout[8];

        /**
         * 获取View数组
         * @param mInflate
         * @param perWidth 每个单位的宽度,其中月份占1份,星期占1.5份
         * @param height 默认的日期栏高度,可用可不用
         * @return
         */
        @Override
        public View[] getDateViews(LayoutInflater mInflate,float perWidth,int height) {
            int heightPx= ScreenUtils.dip2px(DateActivity.this,35);
            View[] views=new View[8];
            View first=mInflate.inflate(R.layout.item_custom_dateview_first,null,false);
            LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams((int) perWidth,heightPx);
            layouts[0]=null;
            views[0]=first;
            first.setLayoutParams(lp);

            //星期设置
            lp=new LinearLayout.LayoutParams((int)(perWidth*1.5),heightPx);
            String[] dateArray=new String[]{"","周一","周二","周三","周四","周五","周六","周日"};
            for(int i=1;i<8;i++){
                View v=mInflate.inflate(R.layout.item_custom_dateview,null,false);
                TextView dayTextView=v.findViewById(R.id.id_week_day);
                layouts[i]=v.findViewById(R.id.id_week_layout);
                views[i]=v;
                layouts[i].setLayoutParams(lp);
                dayTextView.setText(dateArray[i]);
            }
            return views;
        }

        @Override
        public void onHighLight() {
            //初始化背景色
            int color=Color.parseColor("#F4F8F8");
            for(int i=1;i<8;i++){
                layouts[i].setBackgroundColor(color);
            }

            //高亮
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)-1;
            if(dayOfWeek<0) dayOfWeek=7;
            layouts[dayOfWeek].setBackgroundColor(Color.parseColor("#BFF6F4"));
        }

        @Override
        public void onUpdateDate() {
        }
    }

Step3:设置监听

/**
     * 自定义日期栏
     * @see CustomDateAdapter
     */
    protected void customDateView(){
        mTimetableView.setOnDateBuildListener(new CustomDateAdapter());
        mTimetableView.showDateView().updateDateView();
    }

恢复默认日期栏

/**
     * 恢复默认日期栏
     */
    protected void cancelCustomDateView(){
        mTimetableView.setOnDateBuildListener(null);
        mTimetableView.showDateView().updateDateView();
    }

侧边栏

在课程视图的左侧有一列是侧边栏,本节演示如何对侧边栏的属性进行配置以及自定义侧边栏的步骤

准备

添加控件

    <com.zhuangfei.timetable.TimetableView
        android:id="@+id/id_timetableView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.zhuangfei.timetable.TimetableView>

获取控件

mTimetableView = findViewById(R.id.id_timetableView);
List<MySubject> mySubjects = SubjectRepertory.loadDefaultSubjects();

mTimetableView.setSource(mySubjects)
        .setCurWeek(1)
        .showView();

显示时间

    /**
     * 显示时间
     * 设置侧边栏构建监听,TimeSlideAdapter是控件实现的可显示时间的侧边栏
     * 只修改了侧边栏的属性,所以只更新侧边栏即可(性能高),没有必要更新全部(性能低)
     * @see TimeSlideAdapter
     */
    protected void showTime() {
        String[] times = new String[]{
                "8:00", "9:00", "10:10", "11:00",
                "15:00", "16:00", "17:00", "18:00",
                "19:30", "20:30","21:30","22:30"
        };
        TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
        slideAdapter.setTimes(times);
        mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
        mTimetableView.updateSlideView();
    }

隐藏时间

/**
     * 隐藏时间
     * 将侧边栏监听置Null后,会默认使用默认的构建方法,即不显示时间
     * 只修改了侧边栏的属性,所以只更新侧边栏即可(性能高),没有必要更新全部(性能低)
     */
    protected void hideTime() {
        mTimetableView.getScheduleManager().setOnSlideBuildListener(null);
        mTimetableView.updateSlideView();
    }

修改侧边栏背景

/**
     * 修改侧边栏背景
     * 使用new的方式会覆盖掉之前设置的侧边栏的属性值
     * 如果不想覆盖,可以这样:
     * TimeSlideAdapter adapter= (TimeSlideAdapter) mTimetableView.getScheduleManager()
     *      .getOnSlideBuildListener();
     * 使用该方式获取到控件的TimeSlideAdapter对象,对其设置属性即可
     *
     * 在类型强制类型转换之前,你应该调用过以下代码:
     * TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
     * mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
     *
     * 否则在类型转换时会出现异常,请注意
     *
     * @param color
     */
    protected void modifySlideBgColor(int color){
        TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
        slideAdapter.setBackground(color);
        mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
        mTimetableView.updateSlideView();
    }

修改侧边项背景

/**
     * 修改侧边项背景
     * @param color
     */
    protected void modifyItemBgColor(int color){
        TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
        slideAdapter.setItemBackground(color);
        mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
        mTimetableView.updateSlideView();
    }

修改节次文本颜色

/**
     * 修改侧边栏节次文本的颜色值
     * @param color
     */
    protected void modifyItemTextColor(int color){
        TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
        slideAdapter.setTextColor(color);
        mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
        mTimetableView.updateSlideView();
    }

修改时间文本颜色

/**
     * 修改侧边栏时间文本的颜色值
     * @param color
     */
    protected void modifyItemTimeColor(int color){
        String[] times = new String[]{
                "8:00", "9:00", "10:10", "11:00",
                "15:00", "16:00", "17:00", "18:00",
                "19:30", "20:30","21:30","22:30"
        };
        TimeSlideAdapter slideAdapter = new TimeSlideAdapter();
        slideAdapter.setTimes(times).setTimeTextColor(color);
        mTimetableView.getScheduleManager().setOnSlideBuildListener(slideAdapter);
        mTimetableView.updateSlideView();
    }

自定义侧边栏

Step1:创建布局

创建一个XML文件item_custom_slide.xml,该文件的内容可完全自定义

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <TextView
        android:textColor="@color/app_qing2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="top|center_horizontal"
        android:id="@+id/item_slide_textview"/>
</LinearLayout>

Step2:设置监听

需要实现ISchedule.OnSlideBuildListener中的三个方法:

  • setBackground(LinearLayout layout) 用于设置侧边项的背景色,参数为侧边项的View
  • getSlideItemSize() 返回侧边项的个数
  • onBuildSlideItem() 构建侧边项的过程,返回的View是一个侧边项

重点在第三个方法上,它决定了侧边项是如何构建的

/**
     * 自定义侧边栏效果
     * 使用自定义的布局文件实现的文字居顶部的效果(默认居中)
     */
    protected void customSlideView(){
        mTimetableView.getScheduleManager()
                .setOnSlideBuildListener(new ISchedule.OnSlideBuildListener() {
                    @Override
                    public void setBackground(LinearLayout layout) {
                        //暂时不需要关注
                    }

                    @Override
                    public int getSlideItemSize() {
                        //返回侧边栏的Size
                        return 12;
                    }

                    @Override
                    public View onBuildSlideItem(int pos, LayoutInflater inflater, int itemHeight, int marTop) {
                        //获取View并返回,注意设置marTop值
                        View v=inflater.inflate(R.layout.item_custom_slide,null,false);
                        TextView tv=v.findViewById(R.id.item_slide_textview);
                        LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                itemHeight);
                        lp.setMargins(0,marTop,0,0);
                        tv.setLayoutParams(lp);
                        tv.setText((pos+1)+"");
                        return v;
                    }
                });

        mTimetableView.updateSlideView();
    }

侧边栏效果重置

/**
     * 取消自定义的侧边栏,回到默认状态
     * 只需要将监听器置空即可
     */
    protected void cancelCustomSlideView(){
        mTimetableView.getScheduleManager().setOnSlideBuildListener(null);
        mTimetableView.updateSlideView();
    }

课程项样式

本节将演示如何配置课程项的样式

隐藏非本周课程

/**
     * 隐藏非本周课程
     * 修改了内容的显示,所以必须更新全部(性能不高)
     * 建议:在初始化时设置该属性
     */
    protected void hideNonThisWeek() {
        mTimetableView.getScheduleManager().setShowNotCurWeek(false);
        mTimetableView.updateView();
    }

显示非本周课程

/**
     * 显示非本周课程
     * 修改了内容的显示,所以必须更新全部(性能不高)
     * 建议:在初始化时设置该属性
     */
    protected void showNonThisWeek() {
        mTimetableView.getScheduleManager().setShowNotCurWeek(true);
        mTimetableView.updateView();
    }

设置间距以及弧度

/**
     * 设置间距以及弧度
     * 该方法只能同时设置四个角的弧度,设置单个角的弧度可参考下文
     */
    protected void setMarginAndCorner() {
        mTimetableView.getScheduleManager()
                .setCorner(0)
                .setMarTop(0)
                .setMarLeft(0);
        mTimetableView.updateView();
    }

设置单个角弧度

/**
     * 设置角度(四个角分别控制)
     *
     * @param leftTop
     * @param rightTop
     * @param rightBottom
     * @param leftBottom
     */
    public void setCorner(final int leftTop, final int rightTop, final int rightBottom, final int leftBottom) {
        mTimetableView.getScheduleManager()
                .setOnItemBuildListener(new OnItemBuildAdapter() {
                    @Override
                    public void onItemUpdate(FrameLayout layout, TextView textView, TextView countTextView, Schedule schedule, GradientDrawable gd) {
                        super.onItemUpdate(layout, textView, countTextView, schedule, gd);
                        //数组8个元素,四个方向依次为左上、右上、右下、左下,
                        // 每个方向在数组中占两个元素,值相同
                        gd.setCornerRadii(new float[]{leftTop, leftTop, rightTop, rightTop, rightBottom, rightBottom, leftBottom, leftBottom});
                    }
                });
        mTimetableView.updateView();
    }

修改显示的文本

/**
     * 修改显示的文本
     */
    public void buildItemText() {
        mTimetableView.getScheduleManager()
                .setOnItemBuildListener(new OnItemBuildAdapter() {
                    @Override
                    public String getItemText(Schedule schedule, boolean isThisWeek) {
                        if (isThisWeek) return "[本周]" + schedule.getName();
                        return "[非本周]" + schedule.getName();
                    }
                });
        mTimetableView.updateView();
    }

课程构建拦截

效果不能很好实现,存在BUG,不应该再使用,有这种需求可以考虑从数据源中删除某门课程

/**
     * 将名为"计算机组成原理"的课程拦截下来,该课程不会被构建
     */
    public void intercept() {
        mTimetableView.getScheduleManager()
                .setOnItemBuildListener(new OnItemBuildAdapter() {
                    @Override
                    public boolean interceptItemBuild(Schedule schedule) {
                        if (schedule.getName().equals("计算机组成原理")) return true;
                        return false;
                    }
                });
        mTimetableView.updateView();
        Toast.makeText(this,"已拦截《计算机组成原理》",Toast.LENGTH_SHORT).show();
    }

设置非本周课的背景

/**
     * 设置非本周课的背景
     *
     * @param color
     */
    public void setNonThisWeekBgcolor(int color) {
        mTimetableView.getScheduleManager()
                .getColorPool().setUselessColor(color);
        mTimetableView.updateView();
    }

课程重叠的样式

/**
     * 修改课程重叠的样式,在该接口中,你可以自定义出很多的效果
     */
    protected void modifyOverlayStyle() {
        mTimetableView.getScheduleManager()
                .setOnItemBuildListener(new OnItemBuildAdapter() {
                    @Override
                    public void onItemUpdate(FrameLayout layout, TextView textView, TextView countTextView, Schedule schedule, GradientDrawable gd) {
                        super.onItemUpdate(layout, textView, countTextView, schedule, gd);
                        //可见说明重叠,取消角标,添加角度
                        if (countTextView.getVisibility() == View.VISIBLE) {
                            countTextView.setVisibility(View.GONE);
                            gd.setCornerRadii(new float[]{0, 0, 20, 20, 0, 0, 0, 0});
                        }
                    }
                });
        mTimetableView.updateView();
    }

颜色池

颜色池ScheduleColorPool的内部实现是控件维护的一个集合,它管理着课程项的颜色,负责对颜色的存取

获取颜色池

以下代码的返回结果就是一个ScheduleColorPool实例对象

mTimetableView.getScheduleManager().getColorPool();

指定颜色

如果需要让所有课程只在某几种颜色中分配颜色,只需要清空颜色池并加入特定的颜色,在分配颜色时会循环分配颜色池中的颜色

/**
     * 设置指定的颜色,默认情况下颜色池中有一些颜色
     * 所以这里需要先清空一下颜色池
     * @param colors
     */
    public void setColor(int... colors){
        mTimetableView.getScheduleManager()
                .getColorPool()
                .clear()
                .add(colors);
        mTimetableView.updateView();
    }

重置颜色池

重置后,颜色池恢复到初始状态

/**
     * 重置颜色池
     */
    public void resetColor(){
        mTimetableView.getScheduleManager()
                .getColorPool()
                .reset();
        mTimetableView.updateView();
    }

追加颜色

向颜色池中追加颜色,在为课程项分配颜色时,会按照颜色池中的顺序依次取出颜色,所以并不保证追加的颜色一定会被用到

/**
     * 追加颜色
     * @param colors
     */
    public void addColor(int... colors){
        mTimetableView.getScheduleManager()
                .getColorPool()
                .add(colors);
        mTimetableView.updateView();
    }

设置非本周课程颜色

/**
     * 设置非本周课的背景
     *
     * @param color
     */
    public void setNonThisWeekBgcolor(int color) {
        mTimetableView.getScheduleManager()
                .getColorPool().setUselessColor(color);
        mTimetableView.updateView();
    }

替换滚动布局

为什么会有这个功能?想象这样几个场景:下拉反弹效果、下拉刷新效果、监听到滚动的位置、解决滚动布局嵌套导致的滑动冲突。这几个需求都可以使用自定义View的方式来解决。 替换滚动布局的意思是:你可以使用自定义的ScrollView来替换控件中的普通的ScrollView,可以想象它将有更好的扩展性。 本节将演示如何实现一个有下拉反弹效果的课表界面,自定义View的知识不在本节的范围之内,有兴趣可以百度。

自定义View

你需要先准备好一个自定义View,根据你的需求而定,可以参考demo中定义的弹性滚动布局ElasticScrollView

布局文件

准备一个布局文件,命名任意,这里命名为custom_myscrollview.xml,将以下内容复制到布局文件中,然后将根控件换成自定义控件

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none">

    <include layout="@layout/view_content"/>

</ScrollView>

custom_myscrollview.xml中的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<com.zhuangfei.android_timetableview.ElasticScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none">

    <include layout="@layout/view_content"/>

</com.zhuangfei.android_timetableview.ElasticScrollView>

设置监听

/**
         * 过程很简单,步骤如下:
         * 1.创建一个xml文件,命名为custom_myscrollview.xml
         * 2.拷贝一段代码至该文件中,具体内容可以参见custom_myscrollview.xml
         * 3.将根布局控件修改为自定义的控件,其他内容无需修改
         * 4.设置setOnScrollViewBuildListener()并实现其方法,将自定义的xml转换为View返回即可
         *
         */
        mTimetableView.setSource(mySubjects)
                .setOnScrollViewBuildListener(new ISchedule.OnScrollViewBuildListener() {
                    @Override
                    public View getScrollView(LayoutInflater mInflate) {
                        return mInflate.inflate(R.layout.custom_myscrollview, null, false);
                    }
                })
                .showView();

工具类

控件提供了一个工具类,可以方便的以无界面的方式操作课程数据,本节演示如何使用工具类实现对课程颜色的可视化展示

列表与适配器

在Activity的布局中放一个ListView

<ListView
        android:id="@+id/id_listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>

item_nonview.xml是ListView中每一项的布局,它的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@color/app_white">

    <TextView
        android:id="@+id/id_nonview_name"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:ellipsize="end"
        android:singleLine="true"/>

    <TextView
        android:id="@+id/id_nonview_color"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="15dp"/>
</RelativeLayout>

布局文件准备好之后,需要一个适配器

public class NonViewAdapter extends BaseAdapter {

    List<Schedule> schedules;
    Context context;
    LayoutInflater inflater;

    public NonViewAdapter(Context context, List<Schedule> schedules) {
        this.context = context;
        this.schedules = schedules;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return schedules.size();
    }

    @Override
    public Object getItem(int i) {
        return schedules.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {
        View mView = null;
        ViewHolder holder;
        if (null == convertView) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.item_nonview, null);
            holder.nameTextView = convertView.findViewById(R.id.id_nonview_name);
            holder.colorTextView = convertView.findViewById(R.id.id_nonview_color);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Schedule schedule= (Schedule) getItem(i);
        ScheduleColorPool colorPool=new ScheduleColorPool(context);
        holder.nameTextView.setText(schedule.getName());
        holder.colorTextView.setBackgroundColor(colorPool.getColorAuto(schedule.getColorRandom()));
        return convertView;
    }

    class ViewHolder {
        TextView nameTextView;
        TextView colorTextView;
    }
}

它是如何将课程的颜色找出来的?看下段代码:

Schedule schedule= (Schedule) getItem(i);
ScheduleColorPool colorPool=new ScheduleColorPool(context);
holder.colorTextView.setBackgroundColor(colorPool.getColorAuto(schedule.getColorRandom()));

继续看,核心就是这一行,适配器中的数据都是被分配过颜色了(怎么分配的见下文),所谓分配颜色就是给它一个编号,然后拿着编号到颜色池中取颜色,getColorAuto()不会产生数组越界问题,内部使用模运算来循环的在颜色池中取值

colorPool.getColorAuto(schedule.getColorRandom())

设置适配器

listView=findViewById(R.id.id_listview);
adapter=new NonViewAdapter(this,schedules);
listView.setAdapter(adapter);

显示所有课程

protected void all(){
        List<Schedule> list= ScheduleSupport.transform(SubjectRepertory.loadDefaultSubjects());
        list=ScheduleSupport.getColorReflect(list);//分配颜色

        schedules.clear();
        schedules.addAll(list);
        adapter.notifyDataSetChanged();
    }

第一周有课的课程

/**
     * 获取第一周有课的课程并显示出来
     */
    protected void haveTime(){
        List<Schedule> list= ScheduleSupport.transform(SubjectRepertory.loadDefaultSubjects());
        list=ScheduleSupport.getColorReflect(list);//分配颜色

        List<Schedule> result=new ArrayList<>();
        List<Schedule>[] arr=ScheduleSupport.getSubjectInitial(list);

        for(int i=0;i<arr.length;i++){
            List<Schedule> tmpList=arr[i];
            for(Schedule schedule:tmpList){
                if(ScheduleSupport.isThisWeek(schedule,1)){
                    result.add(schedule);
                }
            }
        }

        schedules.clear();
        schedules.addAll(result);
        adapter.notifyDataSetChanged();
    }

周一有课的课程

/**
     * 显示第一周周一有课的课程
     */
    protected void haveTimeWithMonday(){
        List<Schedule> list= ScheduleSupport.transform(SubjectRepertory.loadDefaultSubjects());
        list=ScheduleSupport.getColorReflect(list);//分配颜色
        List<Schedule> tmpList=ScheduleSupport.getTodaySubjects(list,1,0);
        schedules.clear();
        schedules.addAll(tmpList);
        adapter.notifyDataSetChanged();
    }

其他

Javadocs

还有很多的功能我没有展示出来,其他的就靠你自己来探索了,在此之前,我给你一个藏宝图 Javadocs

Download