ListView addHeaderView, konumun bir artmasına neden olur?


97

Aşağıda ListView içeren bir kod parçacığı bulunmaktadır. Bir emptyView ve bir headerView ekledim. HeaderView eklenmesi, onItemClick'teki konumun bir artırılmasına neden olur.

Yani headerView olmadan ilk liste öğesi 0 konumuna sahip olurken, headerView ile ilk liste öğesinin konumu 1 olur!

Bu, adaptörümde hatalara neden oluyor, örneğin getItem () çağırırken ve diğer bazı yöntemleri kullanırken, aşağıya bakın. Garip bir şey: Bağdaştırıcının getView () yönteminde, headerView eklense bile 0 konumlu ilk liste öğesi istenir !!

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

Bazı adaptör yöntemleri:

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

Bu bir headerView eklerken normal davranış mıdır? Ve adaptörümdeki sorunların üstesinden nasıl gelinir?


1
Sorunuz sorumun cevabını içeriyordu. +1
Shashank Degloorkar

Yanıtlar:


113

Bu sorunla yeni karşılaştım ve en iyi yol , başlıkları hesaplamak ListView.getItemAtPosition(position)yerine sürüm ListAdapter.getItem(position)olarak kullanmak gibi görünüyor ListView, yani: -

Bunun yerine şunu yapın:

myListView.getItemAtPosition(position)

1
Çok doğru! bir nedeni için onItemClicksize bir verir parent. Kullanabilirsinizparent.getItemAtPosition(position)
Brais Gabin

3
Bu aslında benim için işe yaramadı, oysa @whuandroid dekore edilmiş / sarmalayıcı adaptör çözümü kullanıyor.
Dori

3
bu durumda da eşyayı dökmeniz gerekir.
njzk2

ListView'a ebeveyn atasam bile benim için çalışmıyor. Sadece pozisyonu
dışlamam

Benim için çalışmıyor. AdapterViewayrıca sadece eklenen listAdapter 'a geçer. return (adapter == null || position < 0) ? null : adapter.getItem(position);
philipp

31

Başlığa tıklama umurunuzda değilse, adaptörünüzün konumunu almak için üstbilgi görünümlerinin sayısını konumdan çıkarın:

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

        }
    });

Bu en iyi cevap olmalı, başlık umrumda değil, listitem umurumda.
Ninja

Bu çözümün en son OS 7.0 için çalışmadığını düşünüyorum
sha

27

ListViewListedeki ilk öğe olacak bir üstbilgi eklerseniz . Sen geçersiz kılarak bunu telafi olabilir getCount()bir öğe daha az dönmek için ancak idare sağlamak getItem(), getItemId()ve böylece başlık 0 konumunda öğe olurdu üzerinde.


6
Bir öğe daha az döndürmek için getCount () 'un geçersiz kılınması işe yaramaz, çünkü o zaman listenin son liste öğesini kaçırırım. Listede sadece 1 öğe varsa getView () asla çağrılmaz. Ayrıca, bağdaştırıcı liste görünümünden ayrıştırılır ve liste görünümüne eklenen bir başlık olup olmadığını bilmez.
d1rk

2
ListItemClick'te konum ayarlayın = konum - 1 eklenmiş bir başlık varsa, bu özel sorunla karşılaştığımda yaptığım şeyin bu olduğunu düşünüyorum, çok düzgün değil, ama düşünebildiğim tek yol
akshaydashrath

3
Sanırım en kolay yol, önerdiğiniz gibi OnItemClickListener'de position = position- (eklenen headerview sayısı) ayarlamak olacaktır. Adaptörümü headerview'ın kendisini işleyecek şekilde değiştirdim, bu nedenle listview üzerinde addHeaderView'ı çağırmam gerekmiyor. Adaptör biraz daha karmaşık olmasına rağmen.
d1rk

22
"Katma headerviews sayısı" ile elde edilebilir:ListView.getHeaderViewsCount()
John

2
Bunun nasıl doğru cevap olduğunu anlamıyorum. @ Ian Warwick doğru olanı gönderdi, ancak sanırım biraz geç kalmış.
sidon

14

Uygulama yaparken AdapterView.OnItemClickListenersadece başlıkları konumdan çıkarıyoruz.

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

13

Herhangi bir kodu değiştirmenize gerek yok. Aşağıdaki kodu kullanmanız yeterlidir.

 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
Döndürülen öğe sadece "Nesne" olduğundan, bu genellikle çevrim gerektirir.
android geliştiricisi

9

Adaptörünüzü kullanmayın, getAdapter'dan 'dekore edilmiş' adaptörü kullanın.


Bu IMO'yu + 1'leyin - sağladığınız adaptör, bir başlık sağladığınızda indeks ofsetini hesaba katan başka bir adaptörle sarılır. Bunun için bu kod, bu sayfanın başka bir yerinde @Ramesh tarafından verilmektedir (size de +1!)
Dori

5

Bunun bir çözümü, kimliği dizine eşlemektir. Temel olarak id'nin listedeki dizini döndürmesini sağlayın ve tıklama dinleyicisi şunları yapacaktır:

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

3

Merhaba, bunu bu şekilde çözebiliriz, önce başlık görünümünüzü oluşturduktan sonra, listenize ekledikten sonra ve setOnClickListener'ı yapamayan son adım. benim için çalışıyor. herhangi bir geri bildirim hoş geldiniz

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

Cevaplar listesinin çok altında, ama bu gerçekten yararlı. Bu değişiklikleri yapmazsanız, başlık görünümünüz dalgalanma efektleri vb. İle tıklanabilir kalacaktır.
Scott Ferguson

0

@Ramesh'in eklemediği çok yeni değil, bazı ekstra bağlamlar eklemek için:

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 () işlevini kullanın Bağdaştırıcının veri kümesi içinde seçili olan öğenin konumunu döndürür. Bu yöntemin üstbilgi veya altbilgi boyutu konusunda endişelenmenize gerek yoktur.


0

Bu birisine yardımcı olabilir, Farid_z ve Philipp'in cevabını geliştirerek, setItemChecked ve setTitle'ı böyle bir şeyle doğru bir şekilde uygulayabiliriz

        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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.