Android ListView的OnItemClickListener详解
我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnItemClickListener。本文主要在于对OnItemClickListener的position和id参数做详细的解释,我相信有些人在这上面走了些弯路。
先来看一下官方的文档
positionThepositionoftheviewintheadapter.
idTherowidoftheitemthatwasclicked.
而这两行字并没有解释清楚position和id的区别。另外,我们还有个Adapter的getView方法。
publicabstractViewgetView(intposition,ViewconvertView,ViewGroupparent)
这里也有一个position。
初步接触ListView的同学,一般会直接继承ArrayAdapter,然后(比如我),就想当然的认为OnItemClick的position和getView的position是一样的啊。于是我们就getItem(position)来获取相应的数据。
那么这段代码有没有错呢?如果有错的话,在什么情况会出错呢?
第一个问题的答案是,当我们为ListView添加headerView或者footerView之后,这段代码就不一定是我们想要的了。
出现问题的原因在于,当我们为ListView添加headerView或者footerView之后,ListView在setAdapter时,做了一些事情,这导致,Adapter和OnItemClickListener中的position含义发生了变化。
我们可以来看看ListView中setAdapter的实现
publicvoidsetAdapter(ListAdapteradapter){ if(mAdapter!=null&&mDataSetObserver!=null){ mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if(mHeaderViewInfos.size()>0||mFooterViewInfos.size()>0){ mAdapter=newHeaderViewListAdapter(mHeaderViewInfos,mFooterViewInfos,adapter); }else{ mAdapter=adapter; }
可以看出,如果这个ListView存在headerView或者footerView的话,那么会在我们传入的adapter外面在封装一层HeaderViewListAdapter,这是一个专门用来自动处理headerView和footerView的adapter。在ListView中,本身不区分headerView,footerView。ListView可以理解成是只负责管理一组View的数组的UI(ViewGroup),headerView和footerView都委托给HeaderViewListAdapter来处理。(从这里也可以看到为什么API文档中提到,addFooterView和addHeaderView要在setAdapter函数之前调用,如果在之后调用,那么就不会生成HeaderViewListAdapter,从而导致显示不出headerView和footerView)。
回到开头的问题,position和id有啥区别。为此,我们找一下position和id是怎么传进来的。
OnItemClickListener在android.widget.AdapterView的publicbooleanperformItemClick(Viewview,intposition,longid)函数中被调用。
performItemClick在android.widget.AbsListView.PerformClick.run()中被调用
privateclassPerformClickextendsWindowRunnnableimplementsRunnable{ intmClickMotionPosition; publicvoidrun(){ //Thedatahaschangedsincewepostedthisactionintheeventqueue, //bailoutbeforebadthingshappen if(mDataChanged)return; finalListAdapteradapter=mAdapter; finalintmotionPosition=mClickMotionPosition; if(adapter!=null&&mItemCount>0&& motionPosition!=INVALID_<strong>POSITION</strong>&& motionPosition<adapter.getCount()&&sameWindow()){ finalViewview=getChildAt(motionPosition-mFirstPosition); //Ifthereisnoview,somethingbadhappened(theviewscrolledoffthe //screen,etc.)andweshouldcanceltheclick if(view!=null){ performItemClick(view,motionPosition,adapter.getItemId(motionPosition)); } } } }
可以看到,position事实上就是ListView中被点击的view的位置。注意,在ListView中是不负责处理headerView和footViewer的,所以,这个位置应该是这个被点击的view在数组[所有的headerView,用户添加的view,所有的footerView]中的位置(请自行参考HeaderViewListAdapter的getView实现)。而id是来自于adapter.getItemId(position)。
对于ArrayAdapter的getItemId函数,实现就是returnposition。id和position是一致的。
然而,对于HeaderViewListAdapter
publiclonggetItemId(int<strong>position</strong>){ intnumHeaders=getHeadersCount(); if(mAdapter!=null&&<strong>position</strong>>=numHeaders){ intadjPosition=<strong>position</strong>-numHeaders; intadapterCount=mAdapter.getCount(); if(adjPosition<adapterCount){ returnmAdapter.getItemId(adjPosition); } } return-1; }
实现逻辑是,如果position指向了headerView或footerView,那么返回-1,否则,将返回在用户view数组的位置。
也就是说
id=position-headerView的个数(id<headerviewer的个数+用户view的个数),否则=-1
因此,OnItemClickListener的正确实现如下:
voidonItemClick(AdapterViewparent,Viewview,int<strong>position</strong>,longid){ if(id==-1){ //点击的是headerView或者<strong>footerView</strong> return; } intrealPosition=(int)id; Titem=getItem(realPosition); //响应代码 }
相关阅读:
Android中ListViewsetOnItemClickListener点击无效原因分析
以上所述是小编给大家介绍的AndroidListView的OnItemClickListener详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!