欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android ListView position详解及实例代码

程序员文章站 2024-03-05 11:02:06
 我们在使用listview的时候,一般都会为listview添加一个响应事件android.widget.adapterview.onitemclicklistener。...

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

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