超级课程表课表的界面的实现

由于毕业设计有一个功能模块是课程表,就想模仿一下超级课程表的界面,可是开始做的时候却没有一点头绪,百度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部分 -->
	    	<ScrollView
	    	    android: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();
	@Override
	protected 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() {
			@Override
			public void onClick(View arg0) {
				//改变返回按钮的背景,体现出被“按下出”的感觉
				goBackButton.setBackgroundDrawable(CourseTableActivity.this
						.getResources().getDrawable(R.drawable.arrow_left_down));
				// 恢复背景
				mhandler.postDelayed(new Runnable() {
					@Override
					public void run() {
						goBackButton.setBackgroundDrawable(CourseTableActivity.this
								.getResources().getDrawable(R.drawable.arrow_left));
					}
				}, 200);
				mhandler.postDelayed(new Runnable() {
					@Override
					public 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() {
			@Override
			public 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个textview
		for(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));
				else
					tx.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());
					else
						rp.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() {
			@Override
			public 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;
		}
		
	}
	//初始化课程表的messageHandler
	static class CourseInfoInitMessageHandler extends Handler{
		
		WeakReference<CourseTableActivity> mActivity;
		
		public CourseInfoInitMessageHandler(CourseTableActivity activity){
			
			mActivity = new WeakReference<CourseTableActivity>(activity);
		}

		@Override
		public 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};
			//获取课程信息的map
			Map<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>(){
					@Override
					public int compare(CourseInfo arg0, CourseInfo arg1) {
						
						if(arg0.getBeginIndex() < arg1.getBeginIndex())
							return -1;
						else
							return 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;
						// 动态生成课程信息TextView
						TextView 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() {
							@Override
							public 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() {
										@Override
										public 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);
			//获取layout
			popupWindowLayout = 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的adpter
			SimpleAdapter 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() {
				@Override
				public 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();
			//实例化一个popupwindow
			weekListWindow = new PopupWindow(popupWindowLayout, width + 100, width + 120);

		}
		
		weekListWindow.setFocusable(true);
		//设置点击外部可消失
		weekListWindow.setOutsideTouchable(true);
		weekListWindow.setBackgroundDrawable(new BitmapDrawable());
		//消失的时候恢复按钮的背景(消除"按下去"的样式)
		weekListWindow.setOnDismissListener(new OnDismissListener() {
			@Override
			public 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 in
	            if (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();
	    }

		@Override
		public 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;
		}
	}
	@Override
	public int getCount() {
		
		return courseTextViewList.length;
	}

	@Override
	public Object getItem(int index) {
		
		return courseTextViewList[index];
	}

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

	@Override
	public 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

阅读更多
个人分类: android学习笔记
想对作者说点什么? 我来说一句

超级课程表主界面demo

2015年12月09日 2.18MB 下载

java实现课程表

2015年12月06日 12KB 下载

Java 课程表管理系统

2010年07月27日 31KB 下载

没有更多推荐了,返回首页

不良信息举报

超级课程表课表的界面的实现

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭