zoukankan      html  css  js  c++  java
  • 当ListView有Header时,onItemClick里的position不正确

    做毕设时遇到这个问题,恰好网上有类似情况,记录一下,转自http://www.cnblogs.com/tt_mc/p/3618000.html,谢谢作者。

    当给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,和我遇到的问题一样,不过这个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  * <p>
     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(当然也包括getItemgetItemId)等方法的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,你可以在保持文章完整和保留本声明的情况下转帖、分发和印刷等。谢谢作者。

  • 相关阅读:
    Selenium之编辑框操作
    Selenium之勾选框操作
    Selenium之单选框操作
    [复习资料]组合计数学习笔记
    ARC104游记
    [被踩计划] 题解 [省选联考 2020 A 卷] 作业题
    题解 [SEERC2019]Game on a Tree
    [被踩计划] 题解 [NOI2020]美食家
    [被踩计划] 题解 [省选联考 2020 A 卷] 组合数问题
    [被踩计划] 题解 括号树
  • 原文地址:https://www.cnblogs.com/ning1121/p/4377707.html
Copyright © 2011-2022 走看看