工具类
https://github.com/zfman/TimetableView
一个开源的、完善的、简洁的课程表控件
控件提供了一个工具类,可以方便的以无界面的方式操作课程数据,本节演示如何使用工具类实现对课程颜色的可视化展示
布局文件
在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();
}
结语
至此,v2.0.0
的讲解就结束了,虽然这个控件的实现原理很简单,我知道的有两种实现方法,超级课程表、课程格子都是用相对布局来实现的,该控件使用线性布局实现。
两种方式各有优劣,使用线性布局+weight的使用和Relative都需要两次测量,但是Relative可以减少一个布局层次已经减少7个布局,比线性布局的实现要好上一点。最开始的版本滑动时有明显卡顿,经过对其优化,滑动性能大幅度提高,目前滑动性能在警戒线之内。
控件实现不难,但是如何灵活的设计却很难(对我来说),我花费了半个月左右的时间重构了v1.0.4
版本
如果感觉不错就帮我点个star吧,蟹蟹~~