在PinnedListView分析一中还有一些细节在本文做一个补充,主要是view的绘制;
一个view在真正被绘制都是通过canvas来做,在ViewGroup内的z子view,一般再次此之前,还需要通过measuring和layout操作来确定绘制之前的大小位置,measuring是来确定view需要显示的确切大小,浏览源码时经常会看到和height、width一起出现的mode,分别是:
- {@link android.view.View.MeasureSpec#UNSPECIFIED}
- {@link android.view.View.MeasureSpec#EXACTLY}
- {@link android.view.View.MeasureSpec#AT_MOST}
根据对原注释的翻译
UNSPECIFIED,表示承载该view的父view没有为该view设置任何明确地大小约束,所以该view的大小可以是需求的任意大小;
EXACTLY,表示父view已经确定该view应该显示的大小,此时将忽略view本身要求的大小
AT_MOST,表示该view有一个上限,大小可以是低于上限的任意值。
为什么要先讲mode,那是因为确定view的大小需要先进行measuring操作,这是就需要传入分别对应于height、width的mode值,
然后紧接着第二部就是layout,传入view要显示的位置和大小,一般来说可以理解为左上角二位坐标点和右下角二位坐标点的四个数值
完成了layout操作的两部之后就可以在合适的地方绘制到界面中,这里选择的是dispatchDraw()方法,dispatch可以理解为分发、调度,放在ViewGroup中就是在绘制子view之前会调用,是个抽象方法,ListView和AbsListView已经分别实现了一次,在这里我的要绘制的顶部固定的view已经说过他不在整个ViewGroup的树状结构内,所以我们先调用super.dispatcheDraw(),把正常的子view绘制走完,然后通过canvas绘制我们需要的子view,先调用save来保存当前matrix等信息到栈内方便待会恢复,因为我们这里会操作并改变canvas的数据,但是之后我们需要把它重置回去,由于我们的current header view并不是简单钉在顶部,当下面的section view划上来时要能继续往上,有被替换的效果,所以这里有一个位移操作,canvas.translate(0, mHeaderOffset),后面还有一步clipRect的操作,目前不是很理解具体是干啥,他是一个native的方法,后面就是draw和restore了。