Android ListView position详解及实例代码

作者:lqh 时间:2023-10-29 03:33:15 

我们在使用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,ListView,position
0
投稿

猜你喜欢

  • idea前后跳转箭头的快捷键

    2022-09-08 10:55:44
  • 详解Guava中EventBus的使用

    2021-09-13 07:36:34
  • Java 数据结构深入理解ArrayList与顺序表

    2023-02-15 14:24:07
  • java实现压缩字符串和java字符串过滤

    2023-01-06 10:35:19
  • java实现简单的图书管理系统

    2022-11-25 03:30:11
  • android使用Path绘制出多边形

    2021-11-11 19:53:38
  • Android中EditText+Button组合导致输入板无法收起的原因分析及解决办法

    2021-10-01 11:27:51
  • springboot-mongodb的多数据源配置的方法步骤

    2022-05-06 12:04:48
  • Android中GPS定位的用法实例

    2021-07-26 23:26:29
  • C# 使用Dictionary复制克隆副本及比较是否相等

    2021-05-29 21:33:06
  • Android开发之SQLite的使用方法

    2022-11-12 05:26:38
  • 详解Unity安卓共享纹理

    2022-07-10 08:18:21
  • java 输入一个数字组成的数组(输出该数组的最大值和最小值)

    2023-11-24 21:41:58
  • Android实现计时与倒计时的常用方法小结

    2023-10-28 07:18:02
  • C#中ManualResetEvent实现线程的暂停与恢复

    2021-06-20 14:59:24
  • 详解C#读写Excel的几种方法

    2022-10-23 14:23:28
  • 解决eclipse启动tomcat时不能加载web项目的问题

    2023-11-15 14:45:01
  • c#中SAPI使用总结——SpVoice的使用方法

    2022-02-20 09:50:07
  • 深入了解C#多线程安全

    2023-08-08 19:43:32
  • Spring Security验证流程剖析及自定义验证方法

    2023-10-01 22:05:58
  • asp之家 软件编程 m.aspxhome.com