Android ListView position详解及实例代码

所属分类: 软件编程 / Android 阅读数: 35
收藏 0 赞 0 分享

 我们在使用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设计登录界面、找回密码、注册功能

这篇文章主要为大家详细介绍了Android设计登录界面的方法,Android实现找回密码、注册功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android通过手势实现答题器翻页效果

这篇文章主要为大家详细介绍了Android通过手势实现答题器翻页效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android采用双缓冲技术实现画板

这篇文章主要为大家详细介绍了Android采用双缓冲技术实现画板的相关资料,思路清晰,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android开发之毛玻璃效果实例代码

这篇文章主要给大家分享android开发之毛玻璃效果的实例代码,非常具有参考借鉴价值,感兴趣的朋友一起学习吧
收藏 0 赞 0 分享

Android实现桌面悬浮窗、蒙板效果实例代码

这篇文章主要介绍了Android实现桌面悬浮窗、蒙板效果实例代码的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

深入解读Android的Volley库的功能结构

这篇文章主要介绍了Android的Volley开发框架的功能结构,Volley是Android开发中网络部分的一大利器,包含很多HTTP协议通信的相关操作,需要的朋友可以参考下
收藏 0 赞 0 分享

Android开发中使用Volley库发送HTTP请求的实例教程

这篇文章主要介绍了Android开发中使用Volley库发送HTTP请求的实例教程,包括创建Volley单例的基本知识与取消Request请求的技巧等,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿QQ聊天撒花特效 很真实

本文写的这个特效,是关于聊天的,你肯定遇到过,就是你跟人家聊天的时候,比如发送应(么么哒),然后屏幕上全部就是表情了,今天我们就是做这个,撒花的特效,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android的HTTP操作库Volley的基本使用教程

这篇文章主要介绍了Android的HTTP操作库Volley的基本使用教程,包括JSON请求与图片加载等用法的实例,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿水波纹流量球进度条控制器

这篇文章主要介绍了Android仿水波纹流量球进度条控制器的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多