惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - chengbo

Android Studio:为Android定制的IDE 使用Gitolite来对Git的repository实现权限控制 用Debian当路由,来解决BT造成的网络慢的问题 更快的,更好的支持硬件的模拟器 准备再写写东西了 压缩 ViewState 后,与 UpdatePanel 的兼容问题 - chengbo 如何让 firefox 的窗口大小不再被网页脚本改变 52个行之有效的减压方法 用Javascript检查Caps Lock是否按下 如何用C#和SQL获得当前月的第一天和最后一天 每天如何自动编译项目并将之打包添加到VSS中 - chengbo - 博客园 maxthon 2 预览版的邀请 成都古羌科技有限公司招聘 怎样用TSQL建JOB xml参数存储过程 如何在ReadOnly的DataGrid中的让CheckBox列可点击 激情黄健翔 Head first design patterns 读书笔记 – Strategy(策略模式) 双击U盘出现“拒绝访问”的解决方法
当LISTVIEW有HEADER时,ONITEMCLICK里的POSITION不正确
chengbo · 2012-03-09 · via 博客园 - chengbo

今天在做项目的时候,遇到一个问题,记录下来。

当我们给ListView添加一个HeaderView后(代码如下),发现onItemClick方法里的position参数的值不是我们所期望的,比如点击ListView的第一行,我们期望的position是0,可是却是1,也就是说,它是从Header开始计数的。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.home);

mAdapter = new MyAdapter(this);

mListView = (ListView) findViewById(R.id.list);
mListView.addHeaderView(getLayoutInflater().inflate(R.layout.list_header));
mListView.setAdapter(mAdapter);
mListView.setOnClickListener(this);
}

@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
doSomething(mAdapter.getItem(position));
}

Google了下,发现有个老外issue过一个bug,和我遇到的问题一样,不过这个bug被RomainGuy reject掉了,理由是,你用错了,请用getAdapter。回答的太简洁了,完全没法理解,只好又去仔细研究ListView的代码,终于领会他的意思了。把其中addHeaderViewsetAdapter方法贴下来

/**
 * Add a fixed view to appear at the top of the list. If addHeaderView is
 * called more than once, the views will appear in the order they were
 * added. Views added using this call can take focus if they want.
 * <p>
 * NOTE: Call this before calling setAdapter. This is so ListView can wrap
 * the supplied cursor with one that that will also account for header
 * views.
 *
 *
@param v The view to add.
 *
@param data Data to associate with this view
 *
@param isSelectable whether the item is selectable
 
*/
public void addHeaderView(View v, Object data, boolean isSelectable) {
    if (mAdapter != null) {
        throw new IllegalStateException(
                "Cannot add header view to list -- setAdapter has already been called.");
    }

     FixedViewInfo info = new FixedViewInfo();
    info.view = v;
    info.data = data;
    info.isSelectable = isSelectable;
    mHeaderViewInfos.add(info);
}

 /**
 * Sets the data behind this ListView.
 *
 * The adapter passed to this method may be wrapped by a {
@link WrapperListAdapter},
 * depending on the ListView features currently in use. For instance, adding
 * headers and/or footers will cause the adapter to be wrapped.
 *
 *
@param adapter The ListAdapter which is responsible for maintaining the
 *        data backing this list and for producing a view to represent an
 *        item in that data set.
 *
 *
@see #getAdapter()
 
*/
@Override
public void setAdapter(ListAdapter adapter) {
    if (null != mAdapter) {
        mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }

     resetList();
    mRecycler.clear();

     if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
        mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
    } else {
        mAdapter = adapter;
    }

     //其它的一些代码这里省略之...
}

从代码和注释里都可以很清楚的得知,addHeaderView一定要在setAdapter之前调用,如果不是,addHeaderView会抛出一个异常。Android为什么要这样做?因为,在setAdapter的时候,会针对我遇到的这种情况(也就是说,position不正确)做些特殊的处理。setAdapter在内部判断了当前ListView是否有Header或者Footer,如果没有,就直接使用参数传进来的adapter;如果有,则用一个decorated的HeaderViewListAdapter来替换参数。这个HeaderViewListAdapter的使命,就是排除Header和Footer,让position(当然也包括getItemgetItemId等)正确返回。

分析到这里,解决方案就出来了:不要直接使用我们声明的adapter,而是用ListView里的那个decorated adapter。获取它的方法就是调用getAdapter。当然,如果ListView没有Header和Footer,直接使用声明的adapter也没有问题,不过为了方便、避免以后出错,还是统一使用decorated adapter比较好。

把onItemClick改成下面这样,就可以了

@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    doSomething(parent.getAdapter().getItem(position));
}

本文由Roy最初发表于:http://blog.chengbo.net/2012/03/09/onitemclick-return-wrong-position-when-listview-has-headerview.html,你可以在保持文章完整和保留本声明的情况下转帖、分发和印刷等。