ListView addHeaderView causes position to increase by one?

AndroidListviewListadapter

Android Problem Overview


Below is a code snippet with a ListView. I added an emptyView and a headerView. Adding the headerView causes the position in the onItemClick to be increased by one.

So without the headerView the first list element would have position 0, with the headerView the position of the first list element would be 1!

This causes errors in my adapter, e.g. when calling getItem() and using some other methods, see below. Strange thing: In the getView() method of the adapter the first list element is requested with position 0 even if the headerView is added!!

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
		}
	});
}

Some adapter methods:

@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());
}

Is this the normal behaviour when adding a headerView?? And how to overcome the issues in my adapter?

Android Solutions


Solution 1 - Android

I just came across this problem and the best way seems to use the ListView.getItemAtPosition(position) instead of ListAdapter.getItem(position) as the ListView version accounts for the headers, ie:-

Do this instead:

myListView.getItemAtPosition(position)

Solution 2 - Android

If you don't care about the click to the header, subtract the number of header views from the position to get the position for your adapter:

    	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);

		}
	});

Solution 3 - Android

If you add a header to a ListView that becomes the first item in the list. You could compensate for this by overriding the getCount() to return one item less, but ensure you handle the getItem(), getItemId() and so on as the header would be the item in position 0.

Solution 4 - Android

When implementing AdapterView.OnItemClickListener we just subtract the headers from the position.

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

Solution 5 - Android

No need to change any code. Simply use below code.

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

Solution 6 - Android

Do not use your adapter, use 'decorated' adapter from getAdapter.

Solution 7 - Android

One solution to this is to map the id to index. Basically make id return the index in the list and the the click listener would do:

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

Solution 8 - Android

Hi we can resolve this in this way first you create your header view, after inject in your list and the last step unable the setOnClickListener. its works for me. any feedback welcome

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

Solution 9 - Android

Not to add much new that @Ramesh didn't add but some extra context:

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);
        }
    }
});

Solution 10 - Android

Use getSelectedItemPosition() Return the position of the currently selected item within the adapter's data set. This method don't need to worry about the size of headers or footers.

Solution 11 - Android

This might help somebody, improving on Farid_z and Philipp's answer, we can correctly apply the setItemChecked and setTitle with something like this

        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);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiond1rkView Question on Stackoverflow
Solution 1 - AndroidIan WarwickView Answer on Stackoverflow
Solution 2 - Androidfarid_zView Answer on Stackoverflow
Solution 3 - AndroidakshaydashrathView Answer on Stackoverflow
Solution 4 - AndroidphilippView Answer on Stackoverflow
Solution 5 - AndroidRamesh AkulaView Answer on Stackoverflow
Solution 6 - AndroidcycDroidView Answer on Stackoverflow
Solution 7 - AndroidHeinrischView Answer on Stackoverflow
Solution 8 - AndroidEzequiel GarcíaView Answer on Stackoverflow
Solution 9 - AndroidPeter ShannonView Answer on Stackoverflow
Solution 10 - AndroidluhaiworkView Answer on Stackoverflow
Solution 11 - AndroidtruespanView Answer on Stackoverflow