ListView addHeaderView导致位置增加一?


97

下面是带有ListView的代码段。我添加了emptyView和headerView。添加headerView会使onItemClick中的位置增加一。

因此,如果没有headerView,则第一个列表元素的位置为0,而如果标题为headerView,则第一个列表元素的位置将为1!

这会导致我的适配器出错,例如,在调用getItem()并使用其他方法时,请参见下文。奇怪的事情:即使添加了headerView,在适配器的getView()方法中,第一个列表元素的位置也是0。

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ListView list = (ListView) viewSwitcher.findViewById(R.id.list);
    View emptyView = viewSwitcher.findViewById(R.id.empty);
    list.setEmptyView(emptyView);

    View sectionHeading = inflater.inflate(R.layout.heading, list, false);
    TextView sectionHeadingTextView = (TextView) sectionHeading.findViewById(R.id.headingText);
    sectionHeadingTextView.setText(headerText);
    list.addHeaderView(sectionHeading);

    list.setAdapter(listAdapter);

    list.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            listAdapter.getItem(position);
            //Do something with it
        }
    });
}

一些适配器方法:

@Override
public int getViewTypeCount() {
    return TYPE_COUNT;
}

@Override
public int getItemViewType(int position) {
    return (position < items.size()) ? ITEM_NORMAL : ITEM_ADVANCED;
}

    @Override
public Product getItem(int position) {
    return items.get(position);
}
@Override
public boolean areAllItemsEnabled() {
    return false;
}

@Override
public boolean isEnabled(int position) {
    return (position < items.size());
}

这是添加headerView时的正常行为吗?以及如何克服适配器中的问题?


1
您的问题已经回答了我的问题。+1
Shashank Degloorkar 2014年

Answers:


113

我只是碰到这个问题,最好的办法似乎使用ListView.getItemAtPosition(position),而不是ListAdapter.getItem(position)作为ListView版本占头,即: -

改为这样做:

myListView.getItemAtPosition(position)

1
好吧!onItemClick给你parent一个理由。您可以使用parent.getItemAtPosition(position)
Brais Gabin 2013年

3
这实际上对我没有用,而使用@whuandroid装饰的/包装适配器解决方案却可以。
Dori

3
在这种情况下,您也必须投放项目。
njzk2 2013年

即使我将父对象转换为ListView,它也对我不起作用。我只需要排除位置== 0 ...
PawelP 2014年

对我不起作用。AdapterView也只是向下传递到添加的listAdapter。return (adapter == null || position < 0) ? null : adapter.getItem(position);
菲利普

31

如果您不关心单击标题,请从该位置减去标题视图的数量,以获取适配器的位置:

        listView.addHeaderView(inflater.inflate(
                R.layout.my_hdr_layout, null), null, false);
        listView.setAdapter(m_adapter);
        listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            position -= listView.getHeaderViewsCount();
            final MyObject object = m_adapter.getItem(position);

        }
    });

这应该是最好的答案,我不在乎标题,我在乎列表项。
忍者

我觉得这个解决方案并不支持最新的OS 7.0的工作
SHA

27

如果您向标头添加标题ListView,则标头将成为列表中的第一项。您可以通过重写getCount()来少返回一个项目,以弥补这一点,但是请确保您处理了getItem()getItemId()依此类推,因为标题将是位置0的项目。


6
覆盖getCount()以少返回一个项目是行不通的,因为那样我就错过了列表的最后一个列表项。如果列表中只有1个项目,则永远不会调用getView()。此外,适配器与列表视图分离,并且不知道是否有标题添加到列表视图。
d1rk 2012年

2
在ListItemClick设定位置=位置- 1,如果有一个标题连接,我想这就是我,当我面对这个特殊的问题,它不是很整齐,但只有这样,我能想到的那样
akshaydashrath

3
我猜最简单的方法是按照您的建议在OnItemClickListener中设置position = position-(添加的headerviews的数量)。我更改了适配器以处理headerview本身,因此不必在listview上调用addHeaderView。虽然适配器变得有点复杂。
d1rk

22
可以通过以下方式获得“添加的headerview的数量”:ListView.getHeaderViewsCount()
John

2
我看不出这是正确的答案。@伊恩·沃里克(Ian Warwick)发表了正确的评论,但我认为有点晚了。
sidon 2013年

14

实施时,AdapterView.OnItemClickListener我们只是从该位置减去标头。

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    position -= mListView.getHeaderViewsCount();
    // what ever else follows...
}

13

无需更改任何代码。只需使用以下代码。

 list.setOnItemClickListener(new OnItemClickListener() {
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      parent.getAdapter().getItem(position);
         //Do something with it
     }
});

1
这通常需要强制转换,因为返回的项目只是“对象”。
Android开发人员

9

不要使用您的适配器,请使用getAdapter中的“装饰”适配器。


+1是通过此IMO进行的操作-您提供的适配器与另一个适配器包装在一起,当您提供标头时,该适配器将考虑索引偏移量。此代码正在使用的代码是由@Ramesh在此页面的其他位置给出的(也向您+1!)
Dori

5

一种解决方案是将id映射到索引。基本上,使id返回列表中的索引,然后单击侦听器将执行以下操作:

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            listAdapter.getItem((int) id);
}

3

您好,我们可以通过这种方式解决此问题,首先是在插入列表后创建标题视图,最后一步是无法设置setOnClickListener。它对我有用。任何反馈欢迎

ViewGroup headerView = (ViewGroup) getLayoutInflater().inflate(R.layout.your_header, list,false);
list.addHeaderView(headerView);
headerView.setEnabled(false);
headerView.setOnClickListener(null);

它在答案列表的下方,但这确实很有用。如果不进行这些更改,那么你的头视图将继续点击,以涟漪效应等
斯科特弗格森

0

不添加@Ramesh未添加的新内容,而是添加一些额外的上下文:

personList.setOnItemClickListener(new OnItemClickListener() {
    @SuppressWarnings("unchecked")
    public void onItemClick( AdapterView<?> parent, View view, int position, long duration) {
        Map<String, Object> person = (Map<String, Object>) parent.getAdapter().getItem(position);
        if (person != null){

            // If the header was clicked on a null  is returned

            OnPersonUiChangeListener listener = (OnPersonUiChangeListener) getActivity();
            listener.onSelectedPersonChanged(person);
        }
    }
});

0

使用getSelectedItemPosition()返回适配器数据集内当前所选项目的位置。此方法无需担心页眉或页脚的大小。


0

这可能会对某些人有所帮助,可以改善Farid_z和Philipp的答案,我们可以使用类似以下内容的方法正确应用setItemChecked和setTitle

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
        position += 1;
        mDrawerList.setItemChecked(position, true);
        mDrawerList.setSelection(position);
        position -= 1;
        setTitle(mNavigationDrawerItemTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.