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 ?? І як подолати проблеми в моєму адаптері?


1
Ваше запитання мало відповідь на моє запитання. +1
Shashank Degloorkar

Відповіді:


113

Я щойно натрапив на цю проблему, і найкращий спосіб, здається, використовувати ListView.getItemAtPosition(position)замість ListAdapter.getItem(position)цьогоListView версія рахунку для заголовків, а саме: -

Зробіть це замість цього:

myListView.getItemAtPosition(position)

1
Так вірно! onItemClickдає тобі parentпричину. Ви можете використовуватиparent.getItemAtPosition(position)
Brais Gabin

3
Це насправді не працює для мене, тоді як використання @whuandroid оформлене / обгорткове рішення адаптер робить.
Дорі

3
також у цьому випадку ви повинні кинути предмет.
njzk2

Не працює для мене, навіть якщо я привласнив батьків до ListView. Мені просто потрібно виключити позицію == 0 ...
PawelP

Не працює для мене. AdapterViewтакож просто переходить до списку доданого адаптера. 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);

        }
    });

Це має бути найкращою відповіддю, я не дбаю про заголовок, я дбаю про listitem.
Ніндзя

Я думаю, що це рішення не працює для останньої ОС 7.0
ша

27

Якщо ви додасте заголовок до а, ListViewякий стає першим елементом у списку. Ви можете це компенсувати, змінивши значення, getCount()щоб повернути один елемент менше, але переконайтеся, що ви обробляєте тощо getItem(), getItemId()так як заголовок буде елементом у позиції 0.


6
Перевизначення getCount () для повернення на один елемент менше не працює, тому що я пропускаю останній елемент списку списку. Якщо в списку є лише 1 елемент, то getView () ніколи не викликається. Крім того, адаптер від'єднується від перегляду списку і не знає, чи був доданий заголовок до перегляду списку чи ні.
d1rk

2
У встановленому ListItemClick позиції = позиція - 1, якщо додається заголовок, я вважаю, що я зробив, коли зіткнувся з цією проблемою, її не дуже охайно, але єдиний спосіб, про який я можу подумати
akshaydashrath

3
Я думаю, найпростішим способом було б встановити позицію = позиція- (кількість доданих переглядів заголовків) у OnItemClickListener, як ви запропонували. Я змінив адаптер для обробки самого перегляду заголовка, тому мені не потрібно викликати addHeaderView у списку перегляду. Хоча адаптер вийшов трохи складнішим.
d1rk

22
"Кількість доданих переглядів заголовка" можна отримати за допомогою:ListView.getHeaderViewsCount()
Джон

2
Я не бачу, як це правильна відповідь. @Ian Warwick розмістив правильний, однак трохи пізно я припускаю.
Сидон

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
Зазвичай для цього потрібно кастинг, оскільки повертається елемент - це просто "Об'єкт".
андроїд розробник

9

Не використовуйте адаптер, використовуйте «прикрашений» адаптер від getAdapter.


+1 це IMO - це шлях - адаптер, який ви постачаєте, обгортається іншим адаптером, який враховує зміщення індексу при постачанні заголовка. Цей код для цього використовується, наданий @Ramesh в іншому місці на цій сторінці (+1 вам теж!)
Дорі

5

Одним з варіантів цього є зіставлення ідентифікатора для індексу. В основному змушуйте 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 та Philip, ми можемо правильно застосувати 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.