当我们使用ListView,想获取第一个ListItem的高度和宽度的时候,我们需要监听ListView的滚动。从我所犯的错误说起。我有一个ListView,里面有很多数据,我想设置一个固定的头部,然后需要的是获取第一个ListItem的位置,想知道位置,当然先要获得这个view,因为是动态的,需要在onScroll中获取,所以变成这以下:
public class TestListView extends ListFragment implements AbsListView.OnScrollListener { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //获取第一个可见的view View firstView = view.getChildAt(firstVisibleItem); Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth()); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getListView().setOnScrollListener(this); } }
/** * Callback method to be invoked when the list or grid has been scrolled. This will be * called after the scroll has completed * @param view The view whose scroll state is being reported * @param firstVisibleItem the index of the first visible cell (ignore if * visibleItemCount == 0) * @param visibleItemCount the number of visible cells * @param totalItemCount the number of items in the list adaptor */ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount);
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount == 0) { return; } //获取第一个可见的view View firstView = view.getChildAt(firstVisibleItem); Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth()); }
恩,忽略掉当count还为0的情况,这时能运行起来了。
但是,别高兴太早,只要往下滑超过一屏之后,你还是会发现又崩溃了,还是同样的错误,NullPointerException,又是空指针异常。。。搞了一个晚上,我也崩溃了。。。
到最后通过不断调试,发现了一个秘密:onScroll方法中的参数view根本就只是可见的item,不可见的item已经被回收了。这先要理解ListView的机制,它是这样的:当移出屏幕外的item的view是会重新回收利用的,所以ListView中的实际的View只有可见的,不可见的完全被回收了,详情见这里:http://android.amberfog.com/?p=296。
参数view所表示的ListView,并不是表示ListView中有item一样多的View,它只有当前可见的。所以,ListView中第一个就是0,而不是firstVisibleItem的值,代码改成如下就可以正常运行了:
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount == 0) { return; } //获取第一个可见的view View firstView = view.getChildAt(0); Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth()); }