`

Android ListView的OnItemClickListener详解--id和position的区别

 
阅读更多
我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnItemClickListener。本文主要在于对OnItemClickListener的position和id参数做详细的解释,我相信有些人在这上面走了些弯路。

先来看一下官方的文档
position The position of the view in the adapter.
id The row id of the item that was clicked.
而这两行字并没有解释清楚position和id的区别。另外,我们还有个Adapter的getView方法。
public abstract View getView (int position, View convertView, ViewGroup parent)

这里也有一个position。

初步接触ListView的同学,一般会直接继承ArrayAdapter,然后(比如我),就想当然的认为OnItemClick的position和getView的position是一样的啊。于是我们就getItem(position)来获取相应的数据。

那么这段代码有没有错呢?如果有错的话,在什么情况会出错呢?
第一个问题的答案是,当我们为ListView添加headerView或者footerView之后,这段代码就不一定是我们想要的了。

出现问题的原因在于,当我们为ListView添加headerView或者footerView之后,ListView在setAdapter时,做了一些事情,这导致,Adapter和OnItemClickListener中的position含义发生了变化。

我们可以来看看ListView中setAdapter的实现
437  public void setAdapter(ListAdapter adapter) {
438      if (mAdapter != null && mDataSetObserver != null) {
439          mAdapter.unregisterDataSetObserver(mDataSetObserver);
440      }
442      resetList();
443      mRecycler.clear();
445      if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
446          mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
447      } else {
448          mAdapter = adapter;
449      }
可以看出,如果这个ListView存在headerView或者footerView的话,那么会在我们传入的adapter外面在封装一层HeaderViewListAdapter,这是一个专门用来自动处理headerView和footerView的adapter。在ListView中,本身不区分headerView,footerView。ListView可以理解成是只负责管理一组View的数组的UI(ViewGroup),headerView和footerView都委托给HeaderViewListAdapter来处理。(从这里也可以看到为什么API文档中提到,addFooterView和addHeaderView要在setAdapter函数之前调用,如果在之后调用,那么就不会生成HeaderViewListAdapter,从而导致显示不出headerView和footerView)。

回到开头的问题,position和id有啥区别。为此,我们找一下position和id是怎么传进来的。
OnItemClickListener在android.widget.AdapterView的public boolean performItemClick(View view, int position, long id)函数中被调用。
performItemClick在android.widget.AbsListView.PerformClick.run() 中被调用
2497  private class PerformClick extends WindowRunnnable implements Runnable {
2498      int mClickMotionPosition;
2500      public void run() {
2501          // The data has changed since we posted this action in the event queue,
2502          // bail out before bad things happen
2503          if (mDataChanged) return;
2505          final ListAdapter adapter = mAdapter;
2506          final int motionPosition = mClickMotionPosition;
2507          if (adapter != null && mItemCount > 0 &&
2508                  motionPosition != INVALID_POSITION &&
2509                  motionPosition < adapter.getCount() && sameWindow()) {
2510              final View view = getChildAt(motionPosition - mFirstPosition);
2511              // If there is no view, something bad happened (the view scrolled off the
2512              // screen, etc.) and we should cancel the click
2513              if (view != null) {
2514                  performItemClick(view, motionPosition, adapter.getItemId(motionPosition));
2515              }
2516          }
2517      }
2518  }
可以看到,position事实上就是ListView中被点击的view的位置。注意,在ListView中是不负责处理headerView和footViewer的,所以,这个位置应该是这个被点击的view在数组[所有的headerView,用户添加的view,所有的footerView]中的位置(请自行参考HeaderViewListAdapter的getView实现)。而id是来自于adapter.getItemId(position)。

对于ArrayAdapter的getItemId函数,实现就是return position。id和position是一致的。
然而,对于HeaderViewListAdapter

188  public long getItemId(int position) {
189      int numHeaders = getHeadersCount();
190      if (mAdapter != null && position >= numHeaders) {
191          int adjPosition = position - numHeaders;
192          int adapterCount = mAdapter.getCount();
193          if (adjPosition < adapterCount) {
194              return mAdapter.getItemId(adjPosition);
195          }
196      }
197      return -1;
198  }

实现逻辑是,如果position指向了headerView或footerView,那么返回-1,否则,将返回在用户view数组的位置。
也就是说
id=position-headerView的个数(id < headerviewer的个数+用户view的个数),否则=-1
因此,OnItemClickListener的正确实现如下:


1
void onItemClick(AdapterViewparent, View view, int position, long id){
2
    if(id<-1) {
3
        // 点击的是headerView或者footerView
4
        return;
5
    }
6
    int realPosition=(int)id;
7
    T item=getItem(realPosition);
8
    // 响应代码
9
}
原文地址:http://blog.iamzsx.me/show.html?id=147001
分享到:
评论

相关推荐

    Android ListView的OnItemClickListener详解

    在本篇文章中,我们将深入探讨`OnItemClickListener`的`position`和`id`参数,以及它们在实际应用中的差异。 首先,`OnItemClickListener`是`AdapterView`接口的一个实现,适用于包括ListView在内的多种列表视图。...

    android ListView初级到高级详解

    在Android开发中,ListView是一个非常重要的组件,它用于展示大量数据列表,用户可以通过滚动来查看更多的条目。本文将从初级到高级详细讲解ListView的使用,包括基础设置、复杂列表的构建、自定义适配器以及如何...

    android ListView详解 源码实例

    在Android中,我们通常通过Adapter来连接ListView和数据源,Adapter负责将数据转化为可显示的视图。 1. 创建Adapter:自定义一个继承自BaseAdapter的类,实现其中的四个关键方法: - getCount():返回数据源的大小...

    android listview 详解 开发指南

    总结,ListView是Android开发中的核心组件之一,理解并熟练掌握其工作原理和使用技巧对于提升应用的交互体验至关重要。在实际项目中,我们需要根据具体需求灵活运用ListView的各种特性,以实现丰富的功能和优化性能...

    ListView音乐播放器-01简单版.pdf

    1. 创建`ArrayAdapter`对象,并传入`Context`、`Layout`资源ID和音乐列表。 2. 通过`setAdapter`方法将适配器设置给`ListView`。 3. 设置`ListView`的选择模式,例如单选模式`CHOICE_MODE_SINGLE`。 示例代码如下:...

    Android ListView position详解及实例代码

    对OnItemClickListener的position和id参数,我相信有些人在这上面走了些弯路。  在使用listview的时候,我们经常会在listview的监听事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中...

    android listview 自定义样式实例

    在这个类中,你需要实现`getCount()`(返回列表项的数量)、`getItem(int position)`(获取指定位置的数据)、`getItemId(int position)`(返回数据的ID)以及`getView(int position, View convertView, ViewGroup ...

    Android之ListView代码

    创建一个继承自BaseAdapter的自定义Adapter,实现其中的`getCount()`(返回数据项数量)、`getItem(int position)`(获取指定位置的数据项)、`getItemId(int position)`(返回数据项ID)和`getView(int position, ...

    android ListView 详解

    总之,Android的ListView是处理列表数据的核心组件,理解和熟练掌握其使用技巧对Android开发者至关重要。通过适配器、复用机制、事件监听和优化策略,我们可以构建出高效、用户体验良好的列表界面。

    Android ListView组件详解及示例代码

    以下是对Android ListView组件的详细解释和示例代码。 首先,我们来看ListView的基本结构。ListView本身只是一个容器,它不包含任何实际的数据或显示内容。要让ListView显示数据,我们需要创建一个适配器,适配器的...

    android listview adapter

    本篇文章将深入探讨如何在Android中结合ListView和Adapter,以及通过一个简单的实例来说明其工作原理。 1. **ListView的基础理解** - ListView是一个可滚动的视图,用于显示一列可点击的项目。 - 每个列表项通常...

    Android ListView

    更常用的方式是为ListView设置OnItemClickListener,这样可以监听到每个列表项的点击事件,回调方法`onItemClick(AdapterView&lt;?&gt; parent, View view, int position, long id)`提供了点击的位置和相关数据。...

    Android ListView里控件添加监听方法的实例详解

    Android ListView控件添加监听方法的实例详解 Android ListView是一种常用的控件,在Android应用程序中广泛使用。然而,在使用ListView时,经常需要添加监听方法来响应用户的交互操作。今天,我们将详细介绍Android...

    android_pretty_listview_full

    ### Android ListView 使用详解 #### 一、ListView简介 在Android应用开发中,`ListView`是一种常用的UI组件,用于展示一个可以滚动的项目列表。通过合理的布局设计与数据绑定,开发者可以构建出功能丰富的用户...

    Android listView 绘制表格源码

    在Android开发中,ListView是一种常用的组件,用于展示可滚动的列表数据。在许多情况下,我们需要在ListView中绘制复杂的布局,比如表格。本篇文章将详细解析如何在ListView中实现表格源码,以及涉及到的相关知识点...

    安卓Android源码——listView1.rar

    这份"安卓Android源码——listView1.rar"压缩包很可能是包含了一个关于ListView使用和自定义的示例项目。在Android开发中,理解ListView的工作原理以及如何有效地优化其性能是非常重要的知识点。 1. **ListView基本...

    S1结业考试上机题目和答案(listview题目精选)附答案

    【ListView控件详解】 在Android开发中,ListView是用于展示大量数据列表的一种核心组件,它在用户界面设计中扮演着重要角色。S1结业考试的上机题目中,ListView显然是一个重点考察的对象,因为它涉及到数据绑定、...

Global site tag (gtag.js) - Google Analytics