Chinaunix首页 | 论坛 | 博客
  • 博客访问: 346409
  • 博文数量: 102
  • 博客积分: 3140
  • 博客等级: 中校
  • 技术积分: 680
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-28 11:44
个人简介

开阔未来

文章分类

全部博文(102)

文章存档

2015年(10)

2014年(1)

2013年(1)

2012年(4)

2011年(8)

2010年(24)

2009年(51)

2008年(3)

我的朋友

分类: Android平台

2015-02-05 09:42:38

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

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

点击(此处)折叠或打开

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3.     super.onCreate(savedInstanceState);
  4.  
  5.     setContentView(R.layout.home);
  6.  
  7.     mAdapter = new MyAdapter(this);
  8.  
  9.     mListView = (ListView) findViewById(R.id.list);
  10.     mListView.addHeaderView(getLayoutInflater().inflate(R.layout.list_header));
  11.     mListView.setAdapter(mAdapter);
  12.     mListView.setOnClickListener(this);
  13. }
  14.  
  15. @Override
  16. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
  17.     doSomething(mAdapter.getItem(position));
  18. }

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

点击(此处)折叠或打开

  1. /**
  2.  * Add a fixed view to appear at the top of the list. If addHeaderView is
  3.  * called more than once, the views will appear in the order they were
  4.  * added. Views added using this call can take focus if they want.
  5.  *

  6.  * NOTE: Call this before calling setAdapter. This is so ListView can wrap
  7.  * the supplied cursor with one that that will also account for header
  8.  * views.
  9.  *
  10.  * @param v The view to add.
  11.  * @param data Data to associate with this view
  12.  * @param isSelectable whether the item is selectable
  13.  */
  14. public void addHeaderView(View v, Object data, boolean isSelectable) {
  15.     if (mAdapter != null) {
  16.         throw new IllegalStateException(
  17.                 "Cannot add header view to list -- setAdapter has already been called.");
  18.     }
  19.  
  20.     FixedViewInfo info = new FixedViewInfo();
  21.     info.view = v;
  22.     info.data = data;
  23.     info.isSelectable = isSelectable;
  24.     mHeaderViewInfos.add(info);
  25. }
  26.  
  27. /**
  28.  * Sets the data behind this ListView.
  29.  *
  30.  * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
  31.  * depending on the ListView features currently in use. For instance, adding
  32.  * headers and/or footers will cause the adapter to be wrapped.
  33.  *
  34.  * @param adapter The ListAdapter which is responsible for maintaining the
  35.  * data backing this list and for producing a view to represent an
  36.  * item in that data set.
  37.  *
  38.  * @see #getAdapter()
  39.  */
  40. @Override
  41. public void setAdapter(ListAdapter adapter) {
  42.     if (null != mAdapter) {
  43.         mAdapter.unregisterDataSetObserver(mDataSetObserver);
  44.     }
  45.  
  46.     resetList();
  47.     mRecycler.clear();
  48.  
  49.     if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
  50.         mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
  51.     } else {
  52.         mAdapter = adapter;
  53.     }
  54.  
  55.     //其它的一些代码这里省略之...
  56. }


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

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

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

点击(此处)折叠或打开

  1. @Override
  2. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
  3.     doSomething(parent.getAdapter().getItem(position));
  4. }
 本文由Roy最初发表于:http://blog.chengbo.net/2012/03/09/onitemclick-return-wrong-position-when-listview-has-headerview.html,你可以在保持文章完整和保留本声明的情况下转帖、分发和印刷等。



阅读(526) | 评论(0) | 转发(0) |
0

上一篇:Android中的进程(Process)和线程(Thread)

下一篇:没有了

给主人留下些什么吧!~~