Android ListView position详解及实例代码
我们在使用listview的时候,一般都会为listview添加一个响应事件android.widget.adapterview.onitemclicklistener。对onitemclicklistener的position和id参数,我相信有些人在这上面走了些弯路。
在使用listview的时候,我们经常会在listview的监听事件中,例如onitemclicklistener(onitemclick)中,或listview的adapter中(getview、getitem、getitemid等)看到position这个变量。在我们没有为listview添加headerview时,position和数据源集合的索引是一致的,当添加了headerview之后,某些地方的position值就会发生变化,如果不理解清楚,经常会犯一些糊涂。
在listview添加了headerview后, 会将所有view交给headerviewlistadapter来处理,所以我们要在setadapter之前添加headerview或footerview,否则将显示不出来。
@override public void setadapter(listadapter adapter) { if (madapter != null && mdatasetobserver != null) { madapter.unregisterdatasetobserver(mdatasetobserver); } resetlist(); mrecycler.clear(); if (mheaderviewinfos.size() > 0|| mfooterviewinfos.size() > 0) { madapter = new headerviewlistadapter(mheaderviewinfos, mfooterviewinfos, adapter); } else { madapter = adapter; }
先看看headerlistadapter中几个带position参数的方法实现,我们可以看到在传出的position为adjposition,而adjposition均为我们自动去掉了headerview的数量,所以adapter中几个带position变量的方法,得到的position值均和数据源集合索引一致,仔细翻看headerlistadapter中所有需要传出position的方法,position的值都是自动减去了headerview数量。
public view getview(int position, view convertview, viewgroup parent) { // header (negative positions will throw an arrayindexoutofboundsexception) int numheaders = getheaderscount(); if (position < numheaders) { return mheaderviewinfos.get(position).view; } // adapter final int adjposition = position - numheaders; int adaptercount = 0; if (madapter != null) { adaptercount = madapter.getcount(); if (adjposition < adaptercount) { return madapter.getview(adjposition, convertview, parent); } } // footer (off-limits positions will throw an arrayindexoutofboundsexception) return mfooterviewinfos.get(adjposition - adaptercount).view; }
public object getitem(int position) { // header (negative positions will throw an arrayindexoutofboundsexception) int numheaders = getheaderscount(); if (position < numheaders) { return mheaderviewinfos.get(position).data; } // adapter final int adjposition = position - numheaders; int adaptercount = 0; if (madapter != null) { adaptercount = madapter.getcount(); if (adjposition < adaptercount) { return madapter.getitem(adjposition); } } // footer (off-limits positions will throw an arrayindexoutofboundsexception) return mfooterviewinfos.get(adjposition - adaptercount).data; } public long getitemid(int position) { int numheaders = getheaderscount(); if (madapter != null && position >= numheaders) { int adjposition = position - numheaders; int adaptercount = madapter.getcount(); if (adjposition < adaptercount) { return madapter.getitemid(adjposition); } } return -1; }
我们再来分析分析onitemclicklistener的相关源码,onitemclicklistener在android.widget.adapterview的public boolean performitemclick(view view, int position, long id)函数中被调用。而performitemclick是在android.widget.abslistview.performclick.run() 中被调用:
private class performclick extends windowrunnnable implements runnable { int mclickmotionposition; public void run() { // the data has changed since we posted this action in the event queue, // bail out before bad things happen if (mdatachanged) return; final listadapter adapter = madapter; final int motionposition = mclickmotionposition; if (adapter != null && mitemcount > 0 && motionposition != invalid_position && motionposition < adapter.getcount() && samewindow()) { final view view = getchildat(motionposition - mfirstposition); // if there is no view, something bad happened (the view scrolled off the // screen, etc.) and we should cancel the click if (view != null) { performitemclick(view, motionposition, adapter.getitemid(motionposition)); } } } }
从源码中,我们可以看到position对应motionposition,而motionposition通过调试,我们发现就是listview中被点击的位置,所以我们经常在onitemclick中需要获取数据源集合中某个item时,会习惯性写这样代码:sourcelist.get(position-listview.getheaderviewscount())。
我们发现onitemclick还有一个参数,其实就是上面源码中传递给performitemclick的第三个参数,而第三个参数是通过调用adapter的getitemid将motionposition减去了headerview的数量,所以这个参数的结果是与数据源集合的索引一致的。也就是说,我们完全可以使用onitemclick的id这个参数,这个参数是和数据源集合的索引一致的。
另外我们需要注意,如果数据源没有内容,则id的值会为-1,所以我们在使用id时,需要对id做适当判断。
总结:在onitemclicklistener的onitemclick方法中,当我们需要获取点击listview对应的数据源索引时,使用id参数即可。另外除了onitemclick的position参数是点击listview对应view的位置外,adapter中所有position均为数据源索引位置。其实换个角度更容易记,在listview中,position理应是listview中view对应的位置,而在adapter中,理应是数据源的索引位置。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
上一篇: 设计简单的Android图片加载框架
下一篇: 利用委托把用户控件的值显示于网页案例应用