③成绩查询
同样地,成绩查询也采用了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开发,碎片,广播机制与数据持久化技术的各个知识点。更通过自学,学会了安卓绘图,完成了精美的课程表的制作。