Android ListView position详解及实例代码

 我们在使用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中,理应是数据源的索引位置。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android仿斗鱼直播的弹幕效果

    记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆啊,大大小小的公司都要涉足一下直播的领域,用斗鱼的话来讲,现在就是千播之战.而弹幕则无疑是直播功能当中最为重要的一个功能之一,那么今天,我就带着大家一起来实现一个简单的Android端弹幕效果. 分析 首先我们来看一下斗鱼上的弹幕效果,如下图所示: 这是一个Dota2游戏直播的界面,我们可以看到,在游戏界面的上方有很多的弹幕,看直播的观众们就是在这里进行讨论的. 那么这样的一个界面该如何实现呢?其实并

  • Android跳转到通讯录获取用户名称和手机号码的实现思路

    效果图如下所示: 先给大家说下实现android 跳转到通讯录的实现思路: 1.点击跳转到通讯录界面 2.获取通讯录姓名和手机号码 3.回调显示姓名和手机号码 1首先是跳转到通讯录界面 Uri uri = Uri.parse("content://contacts/people"); Intent intent = new Intent(Intent.ACTION_PICK, uri); startActivityForResult(intent, 0); 通过设置通讯录url跳转,可

  • Android ListView ImageView实现单选按钮实例

    做Android开发两年的时间,技术稍稍有一些提升,刚好把自己实现的功能写出来,记录一下,如果能帮助到同行的其他人,我也算是做了件好事,哈哈!!废话不多说,先上个图. 先上一段代码: 1 if (lastposition == position){ 2 viewHolder.setImageResource(R.id.iv_yuandian1,R.mipmap.ic_button_checked); 3 } else { 4 viewHolder.setImageResource(R.id.iv

  • Android中转场动画的实现与兼容性处理

    前言 在 Android 5.0 之前,我们已经有了 overridePendingTransition() 方法来实现一些转场效果.然而,在 Android 5.0 以后,转场效果更加炫酷. 比如下面的动画: 一.Android L 中的转场动画 实现转场动画只需三步: 在 res/ 目录下创建 transition 文件夹,在该文件夹下定义界面转场动画和共享元素的动画. 在 res/value/style 文件中为每个 Activity 指定转场动画的 style ,并在 AndroidMa

  • Android 修改系统关机动画的实现

    在Android 系统移植做自己的移动设备,肯定会遇到更改开机或者关机画面,配置自己产品logo 这点是必须的,这些都要在源码中修改,然后编译,下面给大家介绍个关机动画修改,一个简单示例! 文件路径:frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java 在beginShutdownSequence()方法中: private static void beginShutdownSequence

  • Android 矩阵ColorMatrix

    中文名:坐标矩阵 高等数学里有介绍,在图像处理方面,主要是用于平面的缩放.平移.旋转等操作. 在Android里面,Matrix由9个float值构成,是一个3*3的矩阵.最好记住.如下图 各个字段的含义: 上面的sinX和cosX,表示旋转角度的cos值和sin值,注意,旋转角度是按顺时针方向计算的. translateX和translateY表示x和y的平移量.scale是缩放的比例,1是不变,2是表示缩放1/2,这样子. 如何使用 set,pre,post方法 Matrix调用一系列set

  • Android中关于递归和二分法的算法实例代码

    // 1. 实现一个函数,在一个有序整型数组中二分查找出指定的值,找到则返回该值的位置,找不到返回 -1. package demo; public class Mytest { public static void main(String[] args) { int[] arr={1,2,5,9,11,45}; int index=findIndext(arr,0,arr.length-1,12); System.out.println("index="+index); } // 1

  • Android ListView position详解及实例代码

    我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnItemClickListener.对OnItemClickListener的position和id参数,我相信有些人在这上面走了些弯路. 在使用listview的时候,我们经常会在listview的监听事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView.getItem.getIte

  • android 通知Notification详解及实例代码

    android Notification实例详解 1.使用Builder模式来创建 2.必须要设置一个smallIcon,还可以设置setTicker 3.可以设置 setContentTitle,setContentInfo,setContentText,setWhen 4.可以设置setDefaults(闪屏,声音,震动),通过Notification设置flags(能不能被清除) 5.发送需要获取一个NotificationManager(getSystemService来获取);noti

  • Android 文件选择器详解及实例代码

    本文给大家讲解下Android文件选择器的使用.实际上就是获取用户在SD卡中选择的文件或文件夹的路径,这很像C#中的OpenFileDialog控件. 此实例的实现过程很简单,这样可以让大家快速的熟悉Android文件选择器,提高开发效率. 网上曾经见到过一个关于文件选择器的实例,很多人都看过,本实例是根据它修改而成的,但更容易理解,效率也更高,另外,本实例有自己的特点:   1.监听了用户按下Back键的事件,使其返回上一层目录.        2.针对不同的文件类型(文件vs文件夹 , 目标

  • Android ListView组件详解及示例代码

    Android 列表组件 ListView 列表组件是开发中经常用到组件,使用该组件在使用时需要为它提供适配器,由适配器提供来确定显示样式和显示数据. 下面看一个例子: 新建一个项目Lesson8_ListViewTest,Activity name是MainListViewTest . MainListViewTest.java的代码是: package android.basic.lesson8; import android.app.Activity; import android.os.

  • Android 图片选择详解及实例代码

     Android 图片选择 可以达到的效果: 1.第一个图片的位置放照相机,点击打开照相机 2.其余的是显示全部存储的图片,点击一次是查看大图,长按则是每张图片出现一个checkBox,可以进行选择 下面是实例效果图 MainActivity 类 public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickLis

  • Android GPS定位详解及实例代码

    GPS定位是智能手机上一个比较有意思的功能,LBS等服务都有效的利用了GPS定位功能.本文就跟大家分享下Android开发中的GPS定位知识.      一.Android基础知识准备 1.Activity类 每一种移动开发环境都有自己的基类.如J2ME应用程序的基类是midlets,BREW的基类是applets,而Android程序的基类是Activity.这个activity为我们提供了对移动操作系统的基本功能和事件的访问.这个类包含了基本的构造方法,键盘处理,挂起来恢复功能,以及其他底层

  • Android 百分比布局详解及实例代码

    Android 百分比布局 1.引入:compile 'com.android.support:percent:24.0.0' 2.点开源码可以看到,主要有两个布局类PercentFrameLayout和PercentRelativeLayout,一个工具类PercentLayoutHelper. 3.点开布局类比如PercentRelativeLayout的源码,可以看到实现的很简单. public class PercentRelativeLayout extends RelativeLay

  • Android 消息机制详解及实例代码

    Android 消息机制 1.概述 Android应用启动时,会默认有一个主线程(UI线程),在这个线程中会关联一个消息队列(MessageQueue),所有的操作都会被封装成消息队列然后交给主线程处理.为了保证主线程不会退出,会将消息队列的操作放在一个死循环中,程序就相当于一直执行死循环,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数(handlerMessage),执行完成一个消息后则继续循环,若消息队列为空,线程则会阻塞等待.因此不会退出.如下图所示: Handl

  • Android语音识别技术详解及实例代码

    今天从网上找了个例子实现了语音识别,个人感觉挺好玩的,就把代码贴出来与大家分享下: Android中主要通过RecognizerIntent来实现语音识别,其实代码比较简单,但是如果找不到设置,就会抛出异常ActivityNotFoundException,所以我们需要捕捉这个异常.而且语音识别在模拟器上是无法测试的,因为语音识别是访问google云端数据,所以如果手机的网络没有开启,就无法实现识别声音的!一定要开启手机的网络,如果手机不存在语音识别功能的话,也是无法启用识别! 下面是Recog

  • Android Dialog详解及实例代码

     Android Dialog详解及实例代码 概述: Android开发中最常用的就是Dialog类,除了自定义dialog布局,最多的就是用在弹出对话框.进度条.输入框.单选.复选框. 1.选择对话框: AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle("选择对话框"); dialog.setMessage("请选择确认或取消"); dialog.setCance

随机推荐