ListView addHeaderView вызывает увеличение позиции на единицу?

97

Ниже приведен фрагмент кода со ListView. Я добавил emptyView и headerView. Добавление headerView приводит к увеличению позиции в onItemClick на единицу.

Таким образом, без headerView первый элемент списка будет иметь позицию 0, с headerView позиция первого элемента списка будет 1!

Это вызывает ошибки в моем адаптере, например, при вызове getItem () и использовании некоторых других методов, см. Ниже. Странная вещь: в методе адаптера getView () первый элемент списка запрашивается с позицией 0, даже если добавлен headerView !!

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 ?? А как побороть проблемы в моем адаптере?

d1rk
источник
1
В вашем вопросе был ответ на мой вопрос. +1
Shashank Degloorkar

Ответы:

113

Я просто наткнулся на эту проблему , и лучший способ , кажется, использовать ListView.getItemAtPosition(position)вместо ListAdapter.getItem(position)как ListViewверсия счета для заголовков, а именно: -

Вместо этого сделайте это:

myListView.getItemAtPosition(position)
Ян Уорвик
источник
1
Так хорошо! onItemClickдает вам parentпричину. Вы можете использоватьparent.getItemAtPosition(position)
Брайс Габен
3
На самом деле это не сработало для меня, тогда как использование решения адаптера @whuandroid, украшенного / обертки, работает.
Дори
3
Также в этом случае вы должны разыграть предмет.
njzk2
У меня не работает, даже если я передаю родительский элемент в ListView. Мне просто нужно исключить позицию == 0 ...
PawelP 02
У меня не работает. 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);

        }
    });
farid_z
источник
Это должен быть лучший ответ, меня не волнует заголовок, мне важен элемент списка.
Ninja
Я думаю, что это решение не работает для последней версии OS 7.0
sha
27

Если вы добавите заголовок к a ListView, он станет первым элементом в списке. Вы можете компенсировать это путем переопределения getCount()вернуть один пункт меньше, но убедитесь , что вы обрабатывать getItem(), getItemId()и так далее , как заголовок будет элемент в положении 0.

Акшайдашрат
источник
6
Переопределение getCount () для возврата на один элемент меньше не работает, потому что тогда я пропущу последний элемент списка в списке. Если в списке только 1 элемент, getView () никогда не вызывается. Кроме того, адаптер отделен от представления списка и не знает, был ли добавлен заголовок в представление списка или нет.
d1rk
2
В ListItemClick установите position = position - 1, если есть прикрепленный заголовок, я думаю, что это то, что я сделал, когда столкнулся с этой конкретной проблемой, это не очень аккуратно, но единственный способ, о котором я могу думать
akshaydashrath
3
Я думаю, самый простой способ - установить position = position- (количество добавленных заголовков) в OnItemClickListener, как вы предложили. Я изменил свой адаптер для обработки самого заголовка, поэтому мне не нужно вызывать addHeaderView в списке. Хотя адаптер стал немного сложнее.
d1rk
22
«Количество добавленных просмотров заголовков» можно получить с помощью:ListView.getHeaderViewsCount()
Джон,
2
Я не понимаю, насколько это правильный ответ. @Ian Warwick опубликовал правильный, но, как я полагаю, немного поздно.
sidon
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.

cycDroid
источник
+1, этот IMO - это правильный путь - поставляемый вами адаптер обернут другим адаптером, который учитывает смещение индекса при предоставлении заголовка. Этот код для этого использует это, предоставленный @Ramesh в другом месте на этой странице (+1 вам тоже!)
Дори
5

Одно из решений - сопоставить идентификатор с index. В основном заставьте 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 и Филиппа, мы можем правильно применить 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);
продолжительность жизни
источник