由于毕业设计有一个功能模块是课程表,就想模仿一下超级课程表的界面,可是开始做的时候却没有一点头绪,百度google均无果,在CSDN和知乎上提问了也没人回答(估计是太简单了 大神不愿回答),总之自己鼓捣了几天还是弄出来了,虽然实现的方法很挫。。。因为有好几个人都发私信问我怎么实现的,现在毕设做完了,所以我干脆就写到博客上吧,先上几张效果图:

当时看到超级课程表的界面时,第一个想法就是使用ListView来实现,好不容易把格子画出来了,课程信息不知道怎么放上去····,主要难点有:

1、第一排的8个格子是固定的,下面的课表信息部分是可以滑动的,单用ListView无法实现,即下图。

2、课程信息怎么附着在格子上,并且可以随着课表一起滚动。

放弃了ListView实现的想法,就只有另寻它路了,在CSDN上有一位朋友的回答给了我灵感,即每一个格子都用一个TextView实现。然后课程信息可以使用相对布局,根据课程的时间(节数和天数)算出他的偏移位置,比如星期二的第三、四节课就可以和周二下面的第一个格子保持左对齐和上对齐,并且向下偏移2个格子的距离。这个N个格子和课程信息都放到一个RelativeLayout中,然后再在外面嵌套一个ScrollViewLayout,就可以滚动了,总的布局还是RelayoutLayout,不多说了,直接上代码!

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@drawable/c_bg" ><!-- 最左边空白的格子 -->  <TextView android:id="@+id/test_empty"android:layout_width="wrap_content"android:layout_height="wrap_content"style="@style/courseTableText"android:text="@string/empty"android:background="@drawable/course_text_view_bg"/><!-- 星期一的格子 -->  <TextView android:id="@+id/test_monday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/mon"style="@style/courseTableText"android:layout_toRightOf="@id/test_empty"android:background="@drawable/course_text_view_bg"/><!-- 星期二的格子 --><TextView android:id="@+id/test_tuesday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/tue"style="@style/courseTableText"android:layout_toRightOf="@id/test_monday_course"android:background="@drawable/course_text_view_bg"/><!-- 星期三的格子 --><TextView android:id="@+id/test_wednesday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/wen"style="@style/courseTableText"android:layout_toRightOf="@id/test_tuesday_course"android:background="@drawable/course_text_view_bg"/><!-- 星期四的格子 --><TextView android:id="@+id/test_thursday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/thu"style="@style/courseTableText"android:layout_toRightOf="@id/test_wednesday_course"android:background="@drawable/course_text_view_bg"/><!-- 星期五的格子 --><TextView android:id="@+id/test_friday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/fri"style="@style/courseTableText"android:layout_toRightOf="@id/test_thursday_course"android:background="@drawable/course_text_view_bg"/><!-- 星期六的格子 --><TextView android:id="@+id/test_saturday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/sta"style="@style/courseTableText"android:layout_toRightOf="@id/test_friday_course"android:background="@drawable/course_text_view_bg"/><!-- 星期天的格子 --><TextView android:id="@+id/test_sunday_course"android:layout_width="wrap_content"android:layout_height="wrap_content"style="@style/courseTableText"android:text="@string/sun"android:layout_toRightOf="@id/test_saturday_course"android:background="@drawable/course_table_last_colum"/><!-- 课程表body部分 --><ScrollViewandroid:id="@+id/scroll_body"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@id/test_empty" android:scrollbars="none"><!-- 课程信息 --><RelativeLayout android:layout_width="fill_parent"android:layout_height="wrap_content"android:id="@+id/test_course_rl"></RelativeLayout></ScrollView>
</RelativeLayout>

当然这样做的坏处有:

1、有多少个格子就要生成多少个TextView,实在是有点浪费资源。

2、用TextView表示一个格子,即有边框的TextView,整个课表是由N个TextView组成的,所以就没办法使用一张图当背景了。

当然现在我也想到了改进的方法,其实给课程信息做参照算出偏移位置的只需要一个格子就可以了,所以可以用一个透明的TextView放在星期一的第一个格子的位置作为参照,格子使用view画线实现,就可以使用背景了,也不用生成多个TextView了···这是我的想法,我还没用代码实现,有兴趣的朋友可以自己去试试。

超级课程表还有一个要点就是它的课程展示3D视图,不过那个可以用android自带的gallery实现,网上有现成的代码,拿过来改改就可以了,下面上主要代码

1、CourseTableActivity

package nd.leiyi.crims.activity;import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;import nd.leiyi.crims.R;
import nd.leiyi.crims.adapter.CourseInfoAdapter;
import nd.leiyi.crims.appException.AppException;
import nd.leiyi.crims.constant.UserInfo;
import nd.leiyi.crims.db.CourseInfoDBManager;
import nd.leiyi.crims.gallery3D.CourseInfoGallery;
import nd.leiyi.crims.http.CourseInfoFetcher;
import nd.leiyi.crims.model.CourseInfo;
import nd.leiyi.crims.util.CourseSettingUtil;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;public class CourseTableActivity extends Activity {/** 标题栏文字 */protected TextView textTitle;/** 第一个无内容的格子 */protected TextView empty;/** 星期一的格子 */protected TextView monColum;/** 星期二的格子 */protected TextView tueColum;/** 星期三的格子 */protected TextView wedColum;/** 星期四的格子 */protected TextView thrusColum;/** 星期五的格子 */protected TextView friColum;/** 星期六的格子 */protected TextView satColum;/** 星期日的格子 */protected TextView sunColum;/** 课程表body部分布局 */protected RelativeLayout course_table_layout;/** 选择周数弹出窗口 */protected PopupWindow weekListWindow;/** 显示周数的listview*/protected ListView weekListView;/** 选择周数弹出窗口的layout */protected View popupWindowLayout;/** 课程信息 **/protected Map<String, List<CourseInfo>> courseInfoMap;/** 保存显示课程信息的TextView **/protected List<TextView> courseTextViewList = new ArrayList<TextView>();/** 保存每个textview对应的课程信息 map,key为哪一天(如星期一则key为1) **/protected Map<Integer, List<CourseInfo>> textviewCourseInfoMap = new HashMap<Integer, List<CourseInfo>>();/** 课程格子平均宽度 **/protected int aveWidth;/** 屏幕宽度 **/protected int screenWidth;/** 格子高度 **/protected int gridHeight = 80;/** 最大课程节数 **/protected int maxCourseNum; protected Button goBackButton;protected ProgressDialog pDialog;protected Handler mhandler = new Handler();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//设置自定义标题栏布局requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);setContentView(R.layout.course_table_layout);getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.title);//设置标题栏周数textTitle = (TextView) this.findViewById(R.id.textTile);textTitle.setTextSize(20);textTitle.setPadding(15, 2, 15, 2);//右边白色倒三角Drawable down = this.getResources().getDrawable(R.drawable.title_down);down.setBounds(0, 0, down.getMinimumWidth(), down.getMinimumHeight());textTitle.setCompoundDrawables(null, null, down, null);textTitle.setCompoundDrawablePadding(2);//获得列头的控件empty = (TextView) this.findViewById(R.id.test_empty);monColum = (TextView) this.findViewById(R.id.test_monday_course);tueColum = (TextView) this.findViewById(R.id.test_tuesday_course);wedColum = (TextView) this.findViewById(R.id.test_wednesday_course);thrusColum = (TextView) this.findViewById(R.id.test_thursday_course);friColum = (TextView) this.findViewById(R.id.test_friday_course);satColum  = (TextView) this.findViewById(R.id.test_saturday_course);sunColum = (TextView) this.findViewById(R.id.test_sunday_course);//返回按钮goBackButton = (Button) this.findViewById(R.id.button_go_back);goBackButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {//改变返回按钮的背景,体现出被“按下出”的感觉goBackButton.setBackgroundDrawable(CourseTableActivity.this.getResources().getDrawable(R.drawable.arrow_left_down));// 恢复背景mhandler.postDelayed(new Runnable() {@Overridepublic void run() {goBackButton.setBackgroundDrawable(CourseTableActivity.this.getResources().getDrawable(R.drawable.arrow_left));}}, 200);mhandler.postDelayed(new Runnable() {@Overridepublic void run() {finish();}}, 400);}});// 列表布局文件course_table_layout = (RelativeLayout) this.findViewById(R.id.test_course_rl);DisplayMetrics dm = new DisplayMetrics();  getWindowManager().getDefaultDisplay().getMetrics(dm);//屏幕宽度int width = dm.widthPixels;//平均宽度int aveWidth = width / 8;//给列头设置宽度empty.setWidth(aveWidth * 3/4);monColum.setWidth(aveWidth * 33/32 + 1);tueColum.setWidth(aveWidth * 33/32 + 1);wedColum.setWidth(aveWidth * 33/32 + 1);thrusColum.setWidth(aveWidth * 33/32 + 1);friColum.setWidth(aveWidth * 33/32 + 1);satColum.setWidth(aveWidth * 33/32 + 1);sunColum.setWidth(aveWidth * 33/32 + 1);this.screenWidth = width;this.aveWidth = aveWidth;//初始化body部分init();}/*** 初始化课程表body部分* @param aveWidth*/protected void init(){//获取课表配置信息final SharedPreferences courseSettings = getSharedPreferences("course_setting", Activity.MODE_PRIVATE);//检测是否设置过学期if(courseSettings.getString("currentTerm_" + UserInfo.currentUser.getStuNum(), null) == null){Toast.makeText(CourseTableActivity.this, "您尚未设置当前学期!快去设置吧!", Toast.LENGTH_SHORT).show();return;}//计算出当前的周数final String currentWeekStr = CourseSettingUtil.figureCurrentWeek(courseSettings);if(currentWeekStr.equals("")){textTitle.setText("全部");}else{textTitle.setText("第" + currentWeekStr + "周");}//设置点击事件textTitle.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {//改变背景(体现出被"按下去"的感觉textTitle.setBackgroundDrawable(CourseTableActivity.this.getResources().getDrawable(R.drawable.title_text_bg));//显示弹出窗口showWeekListWindow(textTitle);}});//获取最大课程节数String maxCourseNumStr = courseSettings.getString("maxCourseNum_" + UserInfo.currentUser.getStuNum(), "");if(maxCourseNumStr.equals("")){courseSettings.edit().putString("maxCourseNum_" + UserInfo.currentUser.getStuNum(), "12");maxCourseNum = 12;}else{maxCourseNum = Integer.parseInt(maxCourseNumStr);}DisplayMetrics dm = new DisplayMetrics();  getWindowManager().getDefaultDisplay().getMetrics(dm);//屏幕高度 int height = dm.heightPixels;gridHeight = height / maxCourseNum;//设置课表界面//动态生成12 * maxCourseNum个textviewfor(int i = 1; i <= maxCourseNum; i ++){for(int j = 1; j <= 8; j ++){TextView tx = new TextView(CourseTableActivity.this);tx.setId((i - 1) * 8  + j);//除了最后一列,都使用course_text_view_bg背景(最后一列没有右边框)if(j < 8)tx.setBackgroundDrawable(CourseTableActivity.this.getResources().getDrawable(R.drawable.course_text_view_bg));elsetx.setBackgroundDrawable(CourseTableActivity.this.getResources().getDrawable(R.drawable.course_table_last_colum));//相对布局参数RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(aveWidth * 33 / 32 + 1,gridHeight);//文字对齐方式tx.setGravity(Gravity.CENTER);//字体样式tx.setTextAppearance(this, R.style.courseTableText);//如果是第一列,需要设置课的序号(1 到 12)if(j == 1){tx.setText(String.valueOf(i));rp.width = aveWidth * 3/4;  //设置他们的相对位置if(i == 1)rp.addRule(RelativeLayout.BELOW, empty.getId());elserp.addRule(RelativeLayout.BELOW, (i - 1) * 8);}else{rp.addRule(RelativeLayout.RIGHT_OF, (i - 1) * 8  + j - 1);rp.addRule(RelativeLayout.ALIGN_TOP, (i - 1) * 8  + j - 1);tx.setText("");}tx.setLayoutParams(rp);course_table_layout.addView(tx);}}pDialog = new ProgressDialog(this);pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);pDialog.setMessage("正在加载信息。。。。");pDialog.setIndeterminate(true);pDialog.setCanceledOnTouchOutside(false);pDialog.setCancelable(false);pDialog.show();//获取当前学期final String currentTerm = courseSettings.getString("currentTerm_" + UserInfo.currentUser.getStuNum(), null);//查看这个学期的课程信息是否已经抓取过final boolean hasSetting = courseSettings.getBoolean("Is_" + currentTerm + "_saved_" + UserInfo.currentUser.getStuNum(), false);/**这里写你自己的获取课程信息的方法*/new Thread() {@Overridepublic void run() {CourseInfoDBManager dbManager = new CourseInfoDBManager(CourseTableActivity.this);//打开数据库dbManager.open();try {//入果还没抓取过该学期的课程信息,先抓取if(!hasSetting){//抓取这个学期的课表信息List<CourseInfo> list = CourseInfoFetcher.fetchCourseInfo("", currentTerm, UserInfo.currentUser.getStuNum());//插入课程信息for(CourseInfo courseInfo : list){dbManager.insertCourse(courseInfo, currentTerm);}//设置该学期的课程已经抓取过的标志Editor editor = courseSettings.edit();editor.putBoolean("Is_" + currentTerm + "_saved_" + UserInfo.currentUser.getStuNum(), true);editor.commit();}//从数据库中读取课程信息,存放在courseInfoMap中,key为星期几,value是这一天的课程信息courseInfoMap  = dbManager.query(currentTerm);// 发送更新界面信息Message msg = new Message();if(courseInfoMap.isEmpty()){msg.what = -2;courseInfoInitMessageHandler.sendMessage(msg);return;}int currentWeek = -1;if(!currentWeekStr.equals("")){currentWeek = Integer.parseInt(currentWeekStr);}dbManager.close();InitMessageObj msgObj = new InitMessageObj(aveWidth, currentWeek, screenWidth, maxCourseNum);msg.obj = msgObj;courseInfoInitMessageHandler.sendMessage(msg);} catch (AppException e) {Message msg = new Message();msg.what = -1;courseInfoInitMessageHandler.sendMessage(msg);Log.e("courseInfo_fetch_exception", e.toString());} finally {dbManager.close();}}}.start();}  CourseInfoInitMessageHandler courseInfoInitMessageHandler = new CourseInfoInitMessageHandler(this);static class InitMessageObj{int aveWidth;int currentWeek;int screenWidth;int maxCourseNum;public InitMessageObj(int aveWidth, int currentWeek, int screenWidth, int maxCourseNum) {super();this.aveWidth = aveWidth;this.currentWeek = currentWeek;this.screenWidth = screenWidth;this.maxCourseNum = maxCourseNum;}}//初始化课程表的messageHandlerstatic class CourseInfoInitMessageHandler extends Handler{WeakReference<CourseTableActivity> mActivity;public CourseInfoInitMessageHandler(CourseTableActivity activity){mActivity = new WeakReference<CourseTableActivity>(activity);}@Overridepublic void handleMessage(Message msg) {mActivity.get().pDialog.dismiss();//网络错误if(msg.what == -1){Toast.makeText(mActivity.get(), "获取课程信息失败!请检查您的网络或者稍后再试", Toast.LENGTH_SHORT).show();return;}//没有课程信息if(msg.what == -2){Toast.makeText(mActivity.get(), "教务管理系统中无该学期的课程信息···", Toast.LENGTH_SHORT).show();return;}//五种颜色的背景int[] background = {R.drawable.course_info_blue, R.drawable.course_info_green, R.drawable.course_info_red, R.drawable.course_info_red,R.drawable.course_info_yellow};//获取课程信息的mapMap<String, List<CourseInfo>> courseInfoMap = mActivity.get().courseInfoMap;//一些传过来的参数final InitMessageObj msgObj = (InitMessageObj) msg.obj;//当前周数int currentWeek = msgObj.currentWeek;//最大课程节数int maxCourseNum = msgObj.maxCourseNum;for(Map.Entry<String, List<CourseInfo>> entry: courseInfoMap.entrySet()){//查找出最顶层的课程信息(顶层课程信息即显示在最上层的课程,最顶层的课程信息满足两个条件 1、当前周数在该课程的周数范围内 2、该课程的节数跨度最大CourseInfo upperCourse = null;//list里保存的是一周内某 一天的课程final List<CourseInfo> list = new ArrayList<CourseInfo>(entry.getValue());////按开始的时间(哪一节)进行排序Collections.sort(list, new Comparator<CourseInfo>(){@Overridepublic int compare(CourseInfo arg0, CourseInfo arg1) {if(arg0.getBeginIndex() < arg1.getBeginIndex())return -1;elsereturn 1;}});int lastListSize;do {lastListSize = list.size();Iterator<CourseInfo> iter = list.iterator();//先查找出第一个在周数范围内的课while(iter.hasNext()){CourseInfo c = iter.next();//if(((c.getBeginWeek() <= currentWeek && c.getEndWeek() >= currentWeek) || currentWeek == -1) && c.getEndIndex() <= maxCourseNum){//判断是单周还是双周的课if(c.getCourseType() == CourseInfo.ALL ||(c.getCourseType() == CourseInfo.EVEN && currentWeek % 2 == 0) ||(c.getCourseType() == CourseInfo.ODD && currentWeek % 2 != 0)    ){//从list中移除该项,并设置这节课为顶层课iter.remove();upperCourse = c;break;}}}if(upperCourse != null){List<CourseInfo> courseInfoList = new ArrayList<CourseInfo>();courseInfoList.add(upperCourse);int index = 0;iter = list.iterator();//查找这一天有哪些课与刚刚查找出来的顶层课相交while(iter.hasNext()){CourseInfo c = iter.next();//先判断该课程与upperCourse是否相交,如果相交加入courseInfoList中if((c.getBeginIndex() <= upperCourse.getBeginIndex()&&upperCourse.getBeginIndex() < c.getEndIndex())||(upperCourse.getBeginIndex() <= c.getBeginIndex()&& c.getBeginIndex() < upperCourse.getEndIndex())){courseInfoList.add(c);iter.remove();//在判断哪个跨度大,跨度大的为顶层课程信息if((c.getEndIndex() - c.getEndIndex()) > (upperCourse.getEndIndex() - upperCourse.getBeginIndex())&& ((c.getBeginWeek() <= currentWeek && c.getEndWeek() >= currentWeek) || currentWeek == -1)){upperCourse = c;index ++;}}}//记录顶层课程在courseInfoList中的索引位置final int upperCourseIndex = index;// 动态生成课程信息TextViewTextView courseInfo = new TextView(mActivity.get());courseInfo.setId(1000 + upperCourse.getDay() * 100 + upperCourse.getBeginIndex() * 10 + upperCourse.getId());int id = courseInfo.getId();mActivity.get().textviewCourseInfoMap.put(id, courseInfoList);courseInfo.setText(upperCourse.getCourseName() + "\n@" + upperCourse.getClassRoom());//该textview的高度根据其节数的跨度来设置RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(msgObj.aveWidth * 31 / 32,(mActivity.get().gridHeight - 5) * 2 + (upperCourse.getEndIndex() - upperCourse.getBeginIndex() - 1) * mActivity.get().gridHeight);//textview的位置由课程开始节数和上课的时间(day of week)确定rlp.topMargin = 5 + (upperCourse.getBeginIndex() - 1) * mActivity.get().gridHeight;rlp.leftMargin = 1;// 前面生成格子时的ID就是根据Day来设置的rlp.addRule(RelativeLayout.RIGHT_OF, upperCourse.getDay());//字体居中中courseInfo.setGravity(Gravity.CENTER);//选择一个颜色背景int colorIndex = ((upperCourse.getBeginIndex() - 1) * 8 + upperCourse.getDay()) % (background.length - 1);courseInfo.setBackgroundResource(background[colorIndex]);courseInfo.setTextSize(12);courseInfo.setLayoutParams(rlp);courseInfo.setTextColor(Color.WHITE);//设置不透明度courseInfo.getBackground().setAlpha(222);// 设置监听事件courseInfo.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {Log.i("text_view", String.valueOf(arg0.getId()));Map<Integer, List<CourseInfo>> map = mActivity.get().textviewCourseInfoMap;final List<CourseInfo> tempList = map.get(arg0.getId());if(tempList.size() > 1){//如果有多个课程,则设置点击弹出gallery 3d 对话框LayoutInflater layoutInflater = (LayoutInflater) mActivity.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);View galleryView = layoutInflater.inflate(R.layout.course_info_gallery_layout, null);final Dialog coursePopupDialog = new AlertDialog.Builder(mActivity.get()).create();coursePopupDialog.setCanceledOnTouchOutside(true);coursePopupDialog.setCancelable(true);coursePopupDialog.show();WindowManager.LayoutParams params = coursePopupDialog.getWindow().getAttributes();params.width = LayoutParams.FILL_PARENT;coursePopupDialog.getWindow().setAttributes(params);CourseInfoAdapter adapter = new CourseInfoAdapter(mActivity.get(), tempList, msgObj.screenWidth, msgObj.currentWeek);CourseInfoGallery gallery = (CourseInfoGallery) galleryView.findViewById(R.id.course_info_gallery);gallery.setSpacing(10);gallery.setAdapter(adapter);gallery.setSelection(upperCourseIndex);gallery.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3) {CourseInfo courseInfo = tempList.get(arg2);Intent intent = new Intent();Bundle mBundle = new Bundle();mBundle.putSerializable("courseInfo", courseInfo);intent.putExtras(mBundle);intent.setClass(mActivity.get(), DetailCourseInfoActivity.class);mActivity.get().startActivity(intent);coursePopupDialog.dismiss();}});coursePopupDialog.setContentView(galleryView);}else{Intent intent = new Intent();Bundle mBundle = new Bundle();mBundle.putSerializable("courseInfo", tempList.get(0));intent.putExtras(mBundle);intent.setClass(mActivity.get(), DetailCourseInfoActivity.class);mActivity.get().startActivity(intent);}}});mActivity.get().course_table_layout.addView(courseInfo);mActivity.get().courseTextViewList.add(courseInfo);upperCourse = null;}} while(list.size() < lastListSize && list.size() != 0);}super.handleMessage(msg);}}/*** 显示周数下拉列表悬浮窗* @param parent*/private void showWeekListWindow(View parent){if(weekListWindow == null){LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);//获取layoutpopupWindowLayout = layoutInflater.inflate(R.layout.week_list_layout, null);weekListView = (ListView) popupWindowLayout.findViewById(R.id.week_list_view_body);//禁用滚动条(貌似没用··)weekListView.setVerticalScrollBarEnabled(false);List<Map<String, Object>> weekList = new ArrayList<Map<String, Object>>();//默认25周for(int i = 1; i <= 25; i ++){Map<String, Object> rowData = new HashMap<String, Object>();rowData.put("week_index", "第" + i + "周");weekList.add(rowData);}//设置listview的adpterSimpleAdapter listAdapter = new SimpleAdapter(this, weekList, R.layout.week_list_item_layout, new String[]{"week_index"}, new int[]{R.id.week_list_item});weekListView.setAdapter(listAdapter);weekListView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adpater, View arg1,int arg2, long arg3) {int index = 0;String indexStr = textTitle.getText().toString();indexStr = indexStr.replaceAll("第", "").replaceAll("周", "");if(!indexStr.equals("全部"))index = Integer.parseInt(indexStr);textTitle.setText("第" + (arg2 + 1) + "周");weekListWindow.dismiss();if((arg2 + 1) != index){Log.i("courseTableActivity", "清空当前课程信息");for(TextView tx : courseTextViewList){course_table_layout.removeView(tx);}courseTextViewList.clear();//重新设置课程信息Message msg = new Message();InitMessageObj msgObj = new InitMessageObj(aveWidth, arg2 + 1, screenWidth, maxCourseNum);msg.obj = msgObj;courseInfoInitMessageHandler.sendMessage(msg);}}});int width = textTitle.getWidth();//实例化一个popupwindowweekListWindow = new PopupWindow(popupWindowLayout, width + 100, width + 120);}weekListWindow.setFocusable(true);//设置点击外部可消失weekListWindow.setOutsideTouchable(true);weekListWindow.setBackgroundDrawable(new BitmapDrawable());//消失的时候恢复按钮的背景(消除"按下去"的样式)weekListWindow.setOnDismissListener(new OnDismissListener() {@Overridepublic void onDismiss() {textTitle.setBackgroundDrawable(null);}});weekListWindow.showAsDropDown(parent, -50, 0);}}

2、CourseInfo

package nd.leiyi.crims.model;import java.io.Serializable;public class CourseInfo implements Serializable{/*** */private static final long serialVersionUID = 2074656067805712769L;/** id */private int id;/** 课程名称  */private String courseName;/** 上课教室 */private String classRoom;/** 老师  */private String teacher;/** 上课时间(哪一天)(周一--周日) */private int day;/** 上课时间(哪一节)开始(1--12) */private int beginIndex;/** 上课时间(哪一节)节数(1--12) */private int endIndex;/** 上课时间(哪一周) 开始 */private int beginWeek;/** 上课时间(哪一周) 结束 */private int endWeek;/** 课程类型(单周还是双周) **/private int courseType;public static final int ALL = 1;public static final int ODD = 2;public static final int EVEN = 3;public String getCourseName() {return courseName;}public void setCourseName(String courseName) {this.courseName = courseName;}public String getClassRoom() {return classRoom;}public void setClassRoom(String classRoom) {this.classRoom = classRoom;}public String getTeacher() {return teacher;}public void setTeacher(String teacher) {this.teacher = teacher;}public int getDay() {return day;}public void setDay(int day) {this.day = day;}public int getBeginIndex() {return beginIndex;}public void setBeginIndex(int beginIndex) {this.beginIndex = beginIndex;}public int getEndIndex() {return endIndex;}public void setEndIndex(int endIndex) {this.endIndex = endIndex;}public int getBeginWeek() {return beginWeek;}public void setBeginWeek(int beginWeek) {this.beginWeek = beginWeek;}public int getEndWeek() {return endWeek;}public void setEndWeek(int endWeek) {this.endWeek = endWeek;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getCourseType() {return courseType;}public void setCourseType(int courseType) {this.courseType = courseType;}}

3、CourseInfoGallery

package nd.leiyi.crims.gallery3D;import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;public class CourseInfoGallery extends Gallery {private Camera mCamera = new Camera();private int mMaxRotationAngle = 60;private int mMaxZoom = -60;private int mCoveflowCenter;public CourseInfoGallery(Context context) {super(context);this.setStaticTransformationsEnabled(true);}public CourseInfoGallery(Context context, AttributeSet attrs) {super(context, attrs);this.setStaticTransformationsEnabled(true);}public CourseInfoGallery(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);this.setStaticTransformationsEnabled(true);}public int getMaxRotationAngle() {return mMaxRotationAngle;}public void setMaxRotationAngle(int maxRotationAngle) {mMaxRotationAngle = maxRotationAngle;}public int getMaxZoom() {return mMaxZoom;}public void setMaxZoom(int maxZoom) {mMaxZoom = maxZoom;}private int getCenterOfCoverflow() {return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2+ getPaddingLeft();}private static int getCenterOfView(View view) {return view.getLeft() + view.getWidth() / 2;}protected boolean getChildStaticTransformation(View child, Transformation t) {final int childCenter = getCenterOfView(child);final int childWidth = child.getWidth();int rotationAngle = 0;t.clear();t.setTransformationType(Transformation.TYPE_MATRIX);if (childCenter == mCoveflowCenter) {transformImageBitmap(child, t, 0);} else {rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);if (Math.abs(rotationAngle) > mMaxRotationAngle) {rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle: mMaxRotationAngle;}transformImageBitmap(child, t, rotationAngle);}return true;}protected void onSizeChanged(int w, int h, int oldw, int oldh) {mCoveflowCenter = getCenterOfCoverflow();super.onSizeChanged(w, h, oldw, oldh);}private void transformImageBitmap(View child, Transformation t,int rotationAngle) {mCamera.save();final Matrix imageMatrix = t.getMatrix();final int imageHeight = child.getLayoutParams().height;final int imageWidth = child.getLayoutParams().width;final int rotation = Math.abs(rotationAngle);mCamera.translate(0.0f, 0.0f, 100.0f);// As the angle of the view gets less, zoom inif (rotation < mMaxRotationAngle) {float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));mCamera.translate(0.0f, 0.0f, zoomAmount);}mCamera.rotateY(rotationAngle);mCamera.getMatrix(imageMatrix);imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));mCamera.restore();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_MOVE) {return true;} else {return false;}}}

4、CourseInfoAdapter

package nd.leiyi.crims.adapter;import java.util.List;import nd.leiyi.crims.R;
import nd.leiyi.crims.gallery3D.CourseInfoGallery;
import nd.leiyi.crims.model.CourseInfo;
import android.content.Context;
import android.graphics.Color;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;public class CourseInfoAdapter extends BaseAdapter {private Context context;private TextView[] courseTextViewList;private int screenWidth;private int currentWeek;public CourseInfoAdapter(Context context, List<CourseInfo> courseList, int width, int currentWeek) {super();this.screenWidth = width;this.context = context;this.currentWeek = currentWeek;createGalleryWithCourseList(courseList);}private void createGalleryWithCourseList(List<CourseInfo> courseList){//五种颜色的背景int[] background = {R.drawable.course_info_blue, R.drawable.course_info_green, R.drawable.course_info_red, R.drawable.course_info_red,R.drawable.course_info_yellow};this.courseTextViewList = new TextView[courseList.size()];for(int i = 0; i < courseList.size(); i ++){final CourseInfo course = courseList.get(i);TextView textView = new TextView(context);textView.setText(course.getCourseName() + "@" + course.getClassRoom());textView.setLayoutParams(new CourseInfoGallery.LayoutParams((screenWidth / 6) *3, (screenWidth / 6) *3));textView.setTextColor(Color.WHITE);textView.setGravity(Gravity.CENTER_VERTICAL);textView.setPadding(10, 0, 0, 0);if(course.getBeginWeek() <= currentWeek && course.getEndWeek() >= currentWeek &&(course.getCourseType() == CourseInfo.ALL ||(course.getCourseType() == CourseInfo.EVEN && currentWeek % 2 == 0) ||(course.getCourseType() == CourseInfo.ODD && currentWeek % 2 != 0))){//选择一个颜色背景int colorIndex = ((course.getBeginIndex() - 1) * 8 + course.getDay()) % (background.length - 1);textView.setBackgroundResource(background[colorIndex]);}else{textView.setBackgroundResource(R.drawable.course_info_light_grey);}textView.getBackground().setAlpha(222);
//          textView.setOnClickListener(new OnClickListener() {
//              @Override
//              public void onClick(View arg0) {
//                  // TODO Auto-generated method stub
//                  Intent intent = new Intent();
//                  Bundle mBundle = new Bundle();
//                  mBundle.putSerializable("courseInfo", course);
//                  intent.putExtras(mBundle);
//                  intent.setClass(context, DetailCourseInfoActivity.class);
//                  context.startActivity(intent);
//              }
//          });this.courseTextViewList[i] = textView;}}@Overridepublic int getCount() {return courseTextViewList.length;}@Overridepublic Object getItem(int index) {return courseTextViewList[index];}@Overridepublic long getItemId(int arg0) {return arg0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return courseTextViewList[position];}public float getScale(boolean focused, int offset) {return Math.max(0, 1.0f / (float) Math.pow(2, Math.abs(offset)));}}

5、gallery-3d布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><nd.leiyi.crims.gallery3D.CourseInfoGallery android:id="@+id/course_info_gallery"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"/></LinearLayout>

6、gallery-3d-item

<?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" ><TextView android:id="@+id/course_info_gallery_item"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#ffffff"android:gravity="center_vertical"/></LinearLayout>

7、course_text_view_bg (课程格子背景)

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  <item>  <shape>  <solid android:color="#FFFFFF" />  <stroke  android:width="1dp"  android:color="#a8abad" />  </shape>  </item> <item  android:right="1dp"  android:bottom="1dp">  <shape>  <solid android:color="#FFFFFF" />  <stroke  android:width="1dp"  android:color="#ffffff" />  </shape>  </item>
</layer-list>

8、course_table_last_colum(最后一列的背景,无边框)

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  <item>  <shape>  <solid android:color="#FFFFFF" />  <stroke  android:width="1dp"  android:color="#a8abad" />  </shape>  </item> <item  android:bottom="1dp">  <shape>  <solid android:color="#FFFFFF" />  <stroke  android:width="1dp"  android:color="#ffffff" />  </shape>  </item>
</layer-list>

还有一些布局文件就不贴了。代码太多了··,有兴趣的同学可以在github里下载我的工程···工程比较大,而且后台服务端程序我已经从云服务器上撤销了,所以跑不起来,我也不愿改代码了··

gitbub上的代码已删除

demo版:超级课程表demo

超级课程表课表的界面的实现相关推荐

  1. 仿超级课程表的课程界面设计

    首先看下自己做的课表界面吧 接下来先分析页面布局,从上往下看,第一行是显示标题,第二行是显示时间和周几,使用线性布局,第一列是用来显示节次的,宽度跟后面显示周几的7列不一样,可以用DP来设定:后面7列 ...

  2. Android仿超级课程表的课程界面设计

    - 接下来先分析页面布局,从上往下看,第一行是显示标题,第二行是显示时间和周几,使用线性布局,第一列是用来显示节次的,宽度跟后面显示周几的7列不一样,可以用DP来设定:后面7列宽度可以用权重来分配,行 ...

  3. java毕业设计_超级课程表

    超级课程表mysql数据库创建语句 超级课程表oracle数据库创建语句 超级课程表sqlserver数据库创建语句 超级课程表spring+springMVC+hibernate框架对象(javaB ...

  4. android学习:《超级课程表》的课表界面设计

    <超级课程表>的课表界面设计 话不多说,直接看效果图 下面我们来看<超级课程表的界面> 这样的话,我们需要自定义三种视图: 1.自定义 View方格背景 2.自定义 ViewG ...

  5. php模拟超级课程表,一个功能完善、UI简洁的仿超级课程表的课表控件 TimetableView...

    TimetableView 一个非常漂亮的Android课程表控件,该控件支持的功能: 设置数据源 颜色设置,控件内置17种颜色 触感反馈,每种内置颜色都有对应的三个样式 日期显示与高亮 课表Item ...

  6. 超级课程表导入课程显示服务器繁忙,超级课程表 导入不了课表怎么办详解导入课程表教程...

    超级课程表 导入不了课表怎么办详解导入课程表教程文章由XP7编辑网络收集整理,希望大家喜欢!不知道小编分享的内容是否让你有了新的悸动,或许你的心里已经有了一万个骚点子,也欢迎各位来评论来XP7下载进一 ...

  7. 简单方法实现仿超级课程表界面

    简单方法实现仿超级课程表界面 (这个代码其实是我好久之前写武大课程表的时候自己突发奇想实现的.由于当时代码水平不高,所以想出来的方法可能有点歪门邪道的感觉.现在看来,对于实现的方法又有了许多的想法,不 ...

  8. 【超级课程表】大学校园客户端App(查成绩,一卡通,课表,一键评教,正方系统……)

    原文地址:https://zhuanlan.zhihu.com/p/29776226 githu地址:https://github.com/longer96/CDTU 大一时针对我校开发的校园客户端, ...

  9. 超级课程表导入课表显示服务器繁忙,超级课程表导入不了怎么办 超级课程表怎么导入课程表...

    超级课程表7.8.4 官方安卓版 类型:教育学习大小:13.8M语言:中文 评分:7.5 标签: 立即下载 超级课程表软件可以帮助大家导入一学期的课程表,这样你就可以使用超级课程表随时了解课程信息,不 ...

最新文章

  1. fatal error LNK1169: 找到一个或多个多重定义的符号
  2. 洛谷P4319 变化的道路
  3. java工程如何跑起来的_你编写的Java代码是咋跑起来的?
  4. linux内存操作--ioremap和mmap
  5. 《OpenGL编程指南》一3.2 OpenGL缓存数据
  6. 近期团队博客的摘要 5
  7. 怎么将flv视频转换成mp4格式
  8. “爆炸图!“ArcGIS中制作一张好看的爆炸分析图(附练习数据)
  9. 意大利奢侈品牌-Kiton 华丽进驻北京新光天地-时尚生活-泛高尔夫网
  10. 【小算法】求约数个数
  11. overflow:auto自动滚动到底部(vue)
  12. springboot前后端分离 前端请求图片问题
  13. 虚拟化技术-Qemu-KVM
  14. 导入eclipse项目时select eclipse projects to import显示nothing to show--踩坑记录
  15. 语音控制单片机(python做的上位机控制arduino)
  16. matlab fts2mat,[原创]基于MATLAB的通达信股价数据的复权处理(fantuanxiaot版本)
  17. 韭菜投资ABC:如何判断当前指数便宜还是贵(PE百分位法)
  18. 银行现金管理系统—信必优
  19. System Management Bus
  20. PMP准考证什么时候下载

热门文章

  1. 月报总结|Moonbeam 8月份大事一览
  2. reduce参数的理解
  3. 利用人性弱点的互联网产品(一)贪婪
  4. 50岁的哆啦A梦撞上63岁的卡西欧,数据中台告诉你火花有多大
  5. 还在为图像训练数据少发愁吗?那是因为你还不会这几招
  6. 记录一下我在阿里云自主申请软著的过程和体会
  7. 她毁掉丈夫在美国的菜园,催生出百度,被称为百度勇气的来源……
  8. 初创公司Humane获1亿美元融资:投资方包括OpenAI CEO
  9. 再见了Origin,这才是科研法宝,新手秒出图!
  10. EGSnrc egs_cbct 中的几何定义关系