移动设备交互应用 实验三 我的校园
Posted 上山打老虎D
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移动设备交互应用 实验三 我的校园相关的知识,希望对你有一定的参考价值。
我的校园
一、实验目的与内容:
目的:掌握安卓中活动的编写、自定义用户界面的开发、碎片开发、广播机制以及数据持久化技术等;并能通过对课堂知识进行扩展来完善该界面,并使界面尽量美观。
内容要求:
-
请尽量模拟如下深大校园主页的功能,参考:
https://www1.szu.edu.cn/
-
具体要求:
①该实现的界面在某些地方应体现出如下功能:
a. 界面能对平板与手机平台进行自适应(参考第4章碎片);
b. 能对用户身份有强制下线的功能,比如网络中断,登录界面强行退出并显示提示错误的界面;
c. 界面某些地方体现数据持久化的技术,如文件数据的读取、存储的多种实现方式,并简单阐述几种实现方式具体的适用场景;
d. 界面要比较工整,没必要实现参考界面上的所有子项,能保证自己的界面实现能有扩展到参考界面的能力即可。
②功能并不局限于上面的要求,可以根据自己的理解设计一些新的功能,并在报告文档中进行详细的阐述,作为报告的亮点;
③APP的布局尽快模仿参考界面,如果有较大的困难,可以只实现出右半边部分的界面,并尽量按上面要求进行完善;
④对于某一种功能,可以在不同的子项处采用多种实现方式,并比较这些实现方式的不同及优劣势。 -
参考:尽量多的应用参考书《第一行代码 android》第二版第2章活动、第3章UI开发第4章碎片、第5章广播机制与第6章数据持久化技术的各个知识点。
注意:
- 实验报告中需要有功能的描述、实验结果的截屏图像及详细说明;
- 也欢迎采用其它章节的知识点完成本次实验报告,如果实现的功能言之合理,会考虑酌情加分。
二、实验过程和代码与结果
项目亮点:
①通过数据库实现了登录效果
②页面更贴近实际校园类APP,页面更简洁
③采用动态绘制以适应不同横宽比的设备
④按钮区分各个功能,使进入各个功能更方便
⑤采用listview进行布局各条数据,不将各个数据写死,方便真正投入实用
⑥将每个Adapter和对应的类区分成不同的目录,方便查找
1.“我的校园”APP的构建过程及结果
我将主要分为以下三个方面进行介绍:主页面,登录界面,成绩查询。
①主页面
布局分析:
主页面应该是一个垂直方向的LinearLayout:
(1)显示校园图片的banner:
Banner采用轮播进行布局,先布局好所有的child,每个child都充满整个屏幕,然后拦截touch事件,根据手指滑动的距离调用scrollBy()来滚动,当手指停下的时候计算下个要到达第几个child的意图,根据Scroller和回调函数computeScroll()函数来完成接下来的滚动,这个只是child的滚动,我们看到下面还有四个小圆点,这个我叫做指示器,指示当前到了哪个图片,因为它不用响应事件,完全可以画出来,所以我重写了ViewGroup的draw()方法,在super.draw()之后绘制指示器,计算坐标。注意:重绘的时候需要调用setWillNotDraw(false)这个方法,否则将失效。
(2)一个GridLayout布局
中间的八个功能按钮使用GridLayout完成布局。
(3)一个ListView用来显示新闻
此处定义了一个ListView来进行展示对应的新闻,由于这些数据在实际应用中都来自学校服务器,故应采用一个model来完成数据的交互。
使用ListView时需要一个adapter,此处我自定义了一个adapter。 其中,每一条新闻的布局也是通过xml直接堆叠出来。
(4)底部菜单栏
分析得知,整个菜单栏是一个RelativeLayout,然后里面嵌套一个水平方向的LinearLayout,每一个菜单都是一个垂直方向的LinearLayout。
从上图中可以看到,中间的菜单比其他的菜单要往上面突起一点,也就说超过了父容器LinearLayout的高度,这个属性可以在最外层的RelativeLayout中设置一个属性android:clipChildren属性,否则子child是不能超出父容器的。
此外,要将突出的中间的菜单变为圆角,需要使用shape完成这个操作。
(5)顶部ActionBar
我这里使用了ActionBar,对于默认的ActionBar,要加一个右上角的用户头像,关于左上角的文字直接调用Activity的setTitle()就可以更改了,先加右上角的头像,然后重写Activity的一个回调函数,这样就能创建右上角的用户头像。
②登录界面
点击右上角头像,即可滑出登录界面,此处有一侧滑菜单
(1)侧滑菜单的实现
若要加入侧滑菜单,则要先编写侧滑出菜单的布局。
要实现这种侧滑效果,首先自定义一个滑动Layout继承自RelativeLayout,里面有两个View分别是用来存放内容和菜单布局的,然后记录手指一动的距离更改内容View的leftMargin(注意:只有leftMargin的值是负数才能够向左偏移,如果是正数的话那么会向右压缩),在内容View移动的同时,调用菜单的setTranslateX()方法就可以达到菜单移动了。
实现菜单侧滑的几个主要函数
/**
* 切换菜单的显示和隐藏
*/
public void switchMenu() {
if( mLeftParams.leftMargin == 0) {
showMenu();
} else {
hideMenu();
}
}
/**
* 显示菜单
*/
public void showMenu() {
new SmoothScrollTack().execute(-mLeftEdge, mLeftParams.leftMargin);
}
/**
* 隐藏菜单
*/
public void hideMenu() {
new SmoothScrollTack().execute(0, mLeftParams.leftMargin);
}
(2)登录的实现
此处的登录借助了数据库SQLite进行登录数据验证,获取从文本框输入的字符之后,将获取的用户名与密码与数据库进行比对,并返回结果。
③成绩查询
同样地,成绩查询也采用了ListView以便于实际使用,由于前面介绍过,故不再详细说明。代码如下:
2. 请详细说明“我的校园”APP的功能、出现的关键问题及解决方案
(1)主要功能:
①主页面
②登录功能:
效果如下:
③课表查询:
点击“我的课表”即可查看课表,也可点击周数进行周数切换
④成绩查询:
点击“我的通知”即可查看成绩
(2)遇到问题及解决办法:
Q:ViewGroup为什么不会调用onDraw
A: 正常情况下,我们重写LinearLayout的onDraw方法,它是不会被调用的。下面将分析原因并做解释。
在完成主页面功能栏的布局中,遇到了问题重写LinearLayout的onDraw方法时不会被调用,从而导致错误。
<com.test.demo.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_absolute"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF000000">
</com.test.demo.MyLinearLayout>
大概的代码层次是,MyLinearLayout从LinearLayout派生出来,然后在程序中重载OnDraw。但是,onDraw不会被调用。我们可能会遇到这个问题:如果不给LinearLayout设置一个背景,系统是不会调用onDraw时,也就是说,我们重写的onDraw是不会调用的。当设置一个背景后,onDraw就会被调用。
造成这种现象的原因是继承自LinearLayout,而LinearLayout这是一个容器,ViewGroup本身并没有任何可画的东西,它是一个透明的控件,因些并不会触发onDraw,但是如果给LinearLayout设置一个背景色,其实这个背景色不管你设置成什么颜色,系统会认为LinearLayout上面有东西可画了,因此会调用onDraw方法。
我们可以仔细分析View的源码,它有一个方法View#draw(Canvas)方法,这里面有两个地方调用onDraw,它的条件都是:if (!dirtyOpaque) onDraw(canvas);
也就是说,如果dirtyOpaque是true的话,onDraw就不会调用,而dirtyOpaque的值的计算代码如下:
final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
此外,View还提供了一个重要的方法:setWillNotDraw:
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
通过查阅资料,得知如果想重写onDraw,应调用这个方法来清除flag,所以如果想要重写LinearLayout的onDraw,可以在其构造方法中调用setWillNotDraw方法。 在ViewGroup初始他时,它调用了一个私有方法:initViewGroup,其中setFlags(WILL_NOT_DRAW, DRAW_MASK); 相当于调用了setWillNotDraw(true),因此对于ViewGroup,它就认为是透明的了。
如果我们想要重写onDraw,就需要调用setWillNotDraw(false)
综上所述:
①ViewGroup默认情况下,会被设置成WILL_NOT_DRAW,这是从性能考虑,这样一来,onDraw就不会被调用了。
②如果要重写一个ViweGroup的onDraw方法,有两种方法:在构造函数里面,给其设置一个颜色,如#00000000或在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。
三、实验总结
①透明进度条bug
我的透明进度条原理是不断重绘一个背景图片,然后使用Matrix旋转图片,原先的代码是死循环,代码如下:
protected Void doInBackground(Void... params) {
while( true ) {
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
publishProgress();
}
return null;
}
这样就有一个bug,因为是死循环,当ProgressDialog被dismiss掉之后这个循环并不会销毁,而是一直在循环,这样造成的一个bug就是使用了透明进度条之后侧滑菜单点击就没有反应了,并且,透明进度条在Activity下次启动并不会有旋转的效果,这里修改的办法是将这个while(true)改成判断while( mLoop ) 然后重写ProgressDialog的dismiss()方法:
public void dismiss() {
super.dismiss();
mProgressView.setLoop(false);
}
②通过android绘图来绘课程表界面:
受超级课程表等APP的启发,我自学了android绘图,通过绘图,可以更美观的完成课程表的展示。
分析页面可知:
整个界面是一个垂直的LinearLayout布局,里面放着四个子View:使用include标签加载的布局,普通的LinearLayout,自定义View和周数,自定义View与课程表。
通过CourseDateUI和CourseUI完成绘制:
③实验感想:
通过本次实验,我学会了如何完成不同设备的自适应,也学会了通过数据持久化技术完成登录与用户验证,以及各个文件图片的存储。
也学会了熟练使用UI开发,碎片,广播机制与数据持久化技术的各个知识点。更通过自学,学会了安卓绘图,完成了精美的课程表的制作。
以上是关于移动设备交互应用 实验三 我的校园的主要内容,如果未能解决你的问题,请参考以下文章