打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
当ListView有Header时,onItemClick里的position不正确

今天在做项目的时候,遇到一个问题,记录下来。

当我们给ListView添加一个HeaderView后(代码如下),发现onItemClick方法里的position参数的值不是我们所期望的,比如点击ListView的第一行,我们期望的position是0,可是却是1,也就是说,它是从Header开始计数的。

@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);     setContentView(R.layout.home);     mAdapter = newMyAdapter(this);     mListView = (ListView) findViewById(R.id.list);    mListView.addHeaderView(getLayoutInflater().inflate(R.layout.list_header));    mListView.setAdapter(mAdapter);    mListView.setOnClickListener(this);} @OverridepublicvoidonItemClick(AdapterView<?> parent, View v, intposition, longid) {    doSomething(mAdapter.getItem(position));}

Google了下,发现有个老外issue过一个bug,和我遇到的问题一样,不过这个bug被RomainGuy reject掉了,理由是,你用错了,请用getAdapter。回答的太简洁了,完全没法理解,只好又去仔细研究ListView的代码,终于领会他的意思了。把其中addHeaderViewsetAdapter方法贴下来

/** * Add a fixed view to appear at the top of the list. If addHeaderView is * called more than once, the views will appear in the order they were * added. Views added using this call can take focus if they want. * <p> * NOTE: Call this before calling setAdapter. This is so ListView can wrap * the supplied cursor with one that that will also account for header * views. * * @param v The view to add. * @param data Data to associate with this view * @param isSelectable whether the item is selectable */publicvoidaddHeaderView(View v, Object data, booleanisSelectable) {    if(mAdapter != null) {        thrownewIllegalStateException(                "Cannot add header view to list -- setAdapter has already been called.");    }     FixedViewInfo info = newFixedViewInfo();    info.view = v;    info.data = data;    info.isSelectable = isSelectable;    mHeaderViewInfos.add(info);} /** * Sets the data behind this ListView. * * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, * depending on the ListView features currently in use. For instance, adding * headers and/or footers will cause the adapter to be wrapped. * * @param adapter The ListAdapter which is responsible for maintaining the *        data backing this list and for producing a view to represent an *        item in that data set. * * @see #getAdapter() */@OverridepublicvoidsetAdapter(ListAdapter adapter) {    if(null!= mAdapter) {        mAdapter.unregisterDataSetObserver(mDataSetObserver);    }     resetList();    mRecycler.clear();     if(mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {        mAdapter = newHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);    } else{        mAdapter = adapter;    }     //其它的一些代码这里省略之...}

从代码和注释里都可以很清楚的得知,addHeaderView一定要在setAdapter之前调用,如果不是,addHeaderView会抛出一个异常。Android为什么要这样做?因为,在setAdapter的时候,会针对我遇到的这种情况(也就是说,position不正确)做些特殊的处理。setAdapter在内部判断了当前ListView是否有Header或者Footer,如果没有,就直接使用参数传进来的adapter;如果有,则用一个decorated的HeaderViewListAdapter来替换参数。这个HeaderViewListAdapter的使命,就是排除Header和Footer,让position(当然也包括getItem, getItemId等)正确返回。

分析到这里,解决方案就出来了:不要直接使用我们声明的adapter,而是用ListView里的那个decorated adapter。获取它的方法就是调用getAdapter。当然,如果ListView没有Header和Footer,直接使用声明的adapter也没有问题,不过为了方便、避免以后出错,还是统一使用decorated adapter比较好。

把onItemClick改成下面这样,就可以了

@OverridepublicvoidonItemClick(AdapterView<?> parent, View v, intposition, longid) {    doSomething(parent.getAdapter().getItem(position));}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
安卓*
Android ListView的OnItemClickListener详解
ListView中的观察者模式
Android入门 在ListView中如何进行精确的位置设定
RecyclerView点击事件
Adapter报错:The content of the adapter has changed
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服