1.ListView如何和何时把child加入到自身中
在布局阶段使用AbsListView#onLayout()->ListView#layoutChildren()->RecycleBin#fillActiveViews(),ListView#fillFromTop(int nextTop)->ListView#fillDown(int pos, int nextTop)->makeAndAddView(int position, int y, boolean flow, int childrenLeft,
boolean selected)->setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
boolean selected, boolean recycled)
setupChild中不是我们通常使用addView的方法加入child,而是使用ViewGroup#attachViewToParent(View child, int index, LayoutParams params),这种方法和addView很大的区别是不会去触发requestLayout,而只是触发invalidate,就是说不会每添加一个child都重新测量。
ListView使用attachViewToParent添加child时不触发requestLayout,那么怎么确定child的width/height,left,top,right,bottom。把child attachViewToParent后ListView会在setupchild中为child准备MeasureSpec,然后调用child.measure()。测量完确定了width/height后,就确定child的left,top,right,bottom调用child.layout(),其实在调用setupChild时,已经确定了下一个item的位置left,top,top就是上一个item的bottom+隔条高度,而left和上一个是一致的。这样就在没有触发遍历requestLayout的情况下,单独对一个child进行了测量和布局。
首次添加第一屏child
向Adapter#getView获取child,attachViewToparent,单独测量和布局child。
不断添加child直到刚添加的child的bottom大于ListView的height,说明一屏数据已经满了。
ListView如何滑动所有child
在滚动期间都不会去触发requestLayout,ListView的滑动不是使用mScrollX/Y,而是使用ViewGroup#offsetChildrenTopAndBottom(int offset),其中会把所有child的top和bottom加上offset。
如何确定child滑出或滑出了视线
向上滑的时候,如果顶部的child的bottom<0则说明整个child滑出了视线;如果底部的child的bottom小于ListView的height时说明底部有个新的child滑入视线。
向下滑的时候,如果顶部的child的top大于0时则说明顶部有个新的child滑入视线,如果底部的child的top大于ListView的height时说明这个child已经滑出视线。
如何处理滑出视线和滑出视线的child
当将要把一个滑出视线的child从listView移除时,使用ViewGroup#detachViewFromParent,而不是ViewGroup#removeView,这样的区别也是不会触发requestLayout,而只会触发invalidate。移除的child通过RecycleBind#addScrapView()放入一个数据结构中。需要时通过RecycleBind#getScrapView()获取被移除的child。
使用mScrollX/Y和offsetChildrenTopAndBottom的区别
3.想象一下,如果使用mScrollX/Y实现,ListView不可能创建getCount那么多的View,所以也是和recyclebin一样,创建固定数目的view,假如向上滑动,最上面的view不见了,那么把该view detach了,底部的view开始显示时,再attach,然后把top设为上一个view的bottom,把bottom设为top+height。这样不断上滑,view的top和bottom会不断增大。而使用offsetChildrenTopAndBottom的方式代替mScrollX/Y实现滑动,同样的上滑,这个过程中显示中的view的top和bottom不断减小,而顶部的view滑出视线时,top和bottom为-height和0。底部view开始显示时,top和bottom是listview的高度h和h+height。所以使用offsetChildrenTopAndBottom更优雅。也防止了int类型的top和bottom会超出最大范围,加入数据有上万条这个是有可能的。
参考自:
https://blog.csdn.net/guolin_blog/article/details/44996879