ListView addHeaderView menyebabkan posisi meningkat satu?

97

Di bawah ini adalah potongan kode dengan ListView. Saya menambahkan emptyView dan headerView. Menambahkan headerView menyebabkan posisi di onItemClick bertambah satu.

Jadi tanpa headerView, elemen list pertama akan memiliki posisi 0, dengan headerView, posisi elemen daftar pertama adalah 1!

Ini menyebabkan kesalahan pada adaptor saya, misalnya saat memanggil getItem () dan menggunakan beberapa metode lain, lihat di bawah. Hal yang aneh: Dalam metode getView () dari adaptor, elemen daftar pertama diminta dengan posisi 0 bahkan jika headerView ditambahkan !!

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

Beberapa metode adaptor:

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

Apakah ini perilaku normal saat menambahkan headerView ?? Dan bagaimana cara mengatasi masalah pada adaptor saya?

d1rk
sumber
1
Pertanyaan Anda memiliki jawaban atas pertanyaan saya. +1
Shashank Degloorkar

Jawaban:

113

Saya baru saja menemukan masalah ini dan cara terbaik tampaknya menggunakan ListView.getItemAtPosition(position)alih - alih ListAdapter.getItem(position)sebagai ListViewakun versi untuk header, yaitu: -

Lakukan ini sebagai gantinya:

myListView.getItemAtPosition(position)
Ian Warwick
sumber
1
Betul sekali! onItemClickmemberi Anda parentalasan. Anda dapat menggunakanparent.getItemAtPosition(position)
Brais Gabin
3
Ini tidak benar-benar berfungsi untuk saya sedangkan menggunakan solusi adaptor @whuandroid dihiasi / pembungkus tidak.
Dori
3
Anda juga harus membuang item dalam kasus ini.
njzk2
Tidak berfungsi untuk saya bahkan jika saya memasukkan orang tua ke ListView. Saya hanya perlu mengesampingkan posisi == 0 ...
PawelP
Tidak bekerja untuk saya. AdapterViewjuga hanya meneruskan ke listAdapter yang ditambahkan. return (adapter == null || position < 0) ? null : adapter.getItem(position);
philipp
31

Jika Anda tidak peduli tentang klik ke header, kurangi jumlah tampilan header dari posisi untuk mendapatkan posisi adaptor Anda:

        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
sumber
Ini harus menjadi jawaban terbaik, saya tidak peduli dengan header, saya peduli listitemnya.
Ninja
Saya pikir solusi ini tidak berfungsi untuk OS 7.0 terbaru
sha
27

Jika Anda menambahkan header ke ListViewitem itu menjadi item pertama dalam daftar. Anda dapat mengimbanginya dengan menimpa getCount()untuk mengembalikan satu item lebih sedikit, tetapi pastikan Anda menangani getItem(), getItemId()dan seterusnya karena tajuk akan menjadi item di posisi 0.

akshaydashrath
sumber
6
Mengganti getCount () untuk mengembalikan satu item lebih sedikit tidak berfungsi, karena saya kehilangan item daftar terakhir dari daftar. Jika hanya ada 1 item dalam daftar maka getView () tidak pernah dipanggil. Selanjutnya adaptor dipisahkan dari listview dan tidak tahu apakah ada header yang ditambahkan ke listview atau tidak.
d1rk
2
Dalam ListItemClick set position = position - 1 jika ada tajuk yang terpasang, saya pikir itulah yang saya lakukan ketika saya menghadapi masalah khusus ini, itu tidak terlalu rapi, tetapi satu-satunya cara yang dapat saya pikirkan
akshaydashrath
3
Saya kira cara termudah adalah dengan mengatur posisi = posisi- (jumlah tampilan tajuk tambahan) di OnItemClickListener seperti yang Anda sarankan. Saya mengubah adaptor saya untuk menangani tampilan header itu sendiri, jadi saya tidak perlu memanggil addHeaderView di listview. Meskipun adaptor menjadi sedikit lebih kompleks.
d1rk
22
"Jumlah tampilan tajuk tambahan" dapat diperoleh dengan:ListView.getHeaderViewsCount()
John
2
Saya tidak melihat bagaimana ini adalah jawaban yang benar. @Ian Warwick memposting yang benar, betapapun saya kira terlambat.
sidon
14

Saat menerapkan, AdapterView.OnItemClickListenerkami hanya mengurangi header dari posisi.

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

Tidak perlu mengubah kode apa pun. Cukup gunakan kode di bawah ini.

 list.setOnItemClickListener(new OnItemClickListener() {
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      parent.getAdapter().getItem(position);
         //Do something with it
     }
});
Ramesh Akula
sumber
1
Ini biasanya membutuhkan casting, karena item yang dikembalikan hanyalah "Object".
Pengembang android
9

Jangan gunakan adaptor Anda, gunakan adaptor 'dihiasi' dari getAdapter.

cycDroid.dll
sumber
+1 IMO ini adalah cara yang harus dilakukan - adaptor yang Anda berikan dibungkus dengan adaptor lain yang memperhitungkan offset indeks saat Anda memberikan header. Kode untuk ini menggunakan ini diberikan oleh @Ramesh di tempat lain di halaman ini (+1 untuk Anda juga!)
Dori
5

Salah satu solusi untuk ini adalah memetakan id ke indeks. Pada dasarnya membuat id mengembalikan indeks dalam daftar dan pendengar klik akan melakukan:

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

Hai, kami dapat menyelesaikan ini dengan cara ini terlebih dahulu Anda membuat tampilan header, setelah memasukkan dalam daftar Anda dan langkah terakhir tidak dapat mengatur setOnClickListener. itu berhasil untuk saya. setiap umpan balik diterima

ViewGroup headerView = (ViewGroup) getLayoutInflater().inflate(R.layout.your_header, list,false);
list.addHeaderView(headerView);
headerView.setEnabled(false);
headerView.setOnClickListener(null);
Ezequiel García
sumber
Ini jauh di bawah daftar jawaban, tetapi ini sangat berguna. Jika Anda tidak membuat perubahan ini, tampilan tajuk Anda akan tetap dapat diklik, dengan efek riak, dll.
Scott Ferguson
0

Bukan untuk menambahkan banyak hal baru yang tidak ditambahkan @Ramesh tetapi beberapa konteks tambahan:

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);
        }
    }
});
Peter Shannon
sumber
0

Use getSelectedItemPosition () Mengembalikan posisi item yang saat ini dipilih dalam kumpulan data adaptor. Cara ini tidak perlu mengkhawatirkan ukuran header atau footer.

luhaiwork
sumber
0

Ini dapat membantu seseorang, memperbaiki jawaban Farid_z dan Philipp, kita dapat dengan benar menerapkan setItemChecked dan setTitle dengan sesuatu seperti ini

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