zoukankan      html  css  js  c++  java
  • OnItemClickListener 的参数详解(转)

    转载地址:http://blog.iamzsx.me/show.html?id=147001

    我们在使用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 ( != null &&  != null) {
    439          .unregisterDataSetObserver();
    440      }
    442      resetList();
    443      .clear();
    445      if (.size() > 0|| .size() > 0) {
    446           = new HeaderViewListAdapter(, , adapter);
    447      } else {
    448           = 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 () return;
    2505          final ListAdapter adapter = ;
    2506          final int motionPosition = ;
    2507          if (adapter != null &&  > 0 &&
    2508                  motionPosition !=  &&
    2509                  motionPosition < adapter.getCount() && sameWindow()) {
    2510              final View view = getChildAt(motionPosition - );
    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 ( != null && position >= numHeaders) {
    191          int adjPosition = position - numHeaders;
    192          int adapterCount = .getCount();
    193          if (adjPosition < adapterCount) {
    194              return .getItemId(adjPosition);
    195          }
    196      }
    197      return -1;
    198  }
     
    实现逻辑是,如果position指向了headerView或footerView,那么返回-1,否则,将返回在用户view数组的位置。
    也就是说
    id=position-headerView的个数(id < headerviewer的个数+用户view的个数),否则=-1
    因此,OnItemClickListener的正确实现如下:
    void onItemClick(AdapterViewparent, View view, int position, long id){
        if(id<0) {
            // 点击的是headerView或者footerView
            return;
        }
        int realPosition=(int)id;
        T item=getItem(realPosition);
        // 响应代码
    }
     
  • 相关阅读:
    Nginx/Apache图片缩略图技术
    MySQL 备份和恢复
    MySQL主从复制
    xcode针对不同IOS版本的代码编译问题
    java 5 ReadWriteLock
    java 5 Lock
    结对-及格程序查询系统-结对项目总结
    团队-象棋游戏-开发文档
    结对-及格程序查询-最终程序
    结对-及格程序查询-测试过程
  • 原文地址:https://www.cnblogs.com/zhouxiuquan/p/4538536.html
Copyright © 2011-2022 走看看