ListView addHeaderViewにより、位置が1つ増えますか?


97

以下は、ListViewを使用したコードスニペットです。emptyViewとheaderViewを追加しました。headerViewを追加すると、onItemClickの位置が1つ増えます。

したがって、headerViewがない場合、最初のリスト要素の位置は0になり、headerViewを使用すると、最初のリスト要素の位置は1になります。

これにより、アダプタでエラーが発生します。たとえば、getItem()を呼び出して他のいくつかのメソッドを使用すると、以下を参照してください。奇妙なこと:アダプターのgetView()メソッドでは、headerViewが追加されている場合でも、最初のリスト要素が位置0でリクエストされます。

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 2014年

回答:


113

私はこの問題に遭遇したばかりであり、最善の方法は、バージョンのListView.getItemAtPosition(position)代わりにヘッダーを使用するようです:すなわち:ListAdapter.getItem(position)ListView

代わりにこれを行ってください:

myListView.getItemAtPosition(position)

1
しっくり来る!onItemClickあなたは与えparent理由。使用できますparent.getItemAtPosition(position)
Brais Gabin 2013年

3
これは実際には機能しませんでしたが、@ whuandroidの装飾/ラッパーアダプターソリューションを使用すると機能します。
ドリ

3
この場合もアイテムをキャストする必要があります。
njzk2 2013

親をListViewにキャストしても機能しません。私は位置を除外する必要があります== 0 ...
PawelP

私にはうまくいきません。AdapterView追加されたlistAdapterにも渡されます。return (adapter == null || position < 0) ? null : adapter.getItem(position);
フィリップ2015

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

        }
    });

これが最良の答えになるはずです。ヘッダーは気にしません。リストアイテムを気にします。
忍者

このソリューションは最新のOS 7.0では機能しないと思います
sha

27

にヘッダーを追加すると、ListViewそれがリストの最初の項目になります。getCount()1つ少ない項目を返すようにをオーバーライドすることでこれを補正できますが、ヘッダーが位置0の項目になるためgetItem()、を処理するようにしてくださいgetItemId()


6
getCount()をオーバーライドして1つ少ない項目を返すことはできません。それは、リストの最後のリスト項目を見逃しているためです。リストに項目が1つしかない場合、getView()は呼び出されません。さらに、アダプターはリストビューから切り離されており、リストビューにヘッダーが追加されているかどうかがわかりません。
d1rk 2012年

2
ListItemClick set position = position-1で、ヘッダーが添付されている場合、この特定の問題に直面したときに私が行ったのは、きちんとではなく、考えられる唯一の方法です
akshaydashrath

3
あなたが提案したように、最も簡単な方法は、OnItemClickListenerでposition = position-(追加されたヘッダービューの数)を設定することだと思います。headerview自体を処理するようにアダプターを変更したので、リストビューでaddHeaderViewを呼び出す必要はありません。アダプターはもう少し複雑になりましたが。
d1rk 2012

22
:「追加headerviewsの数が」で得ることができるListView.getHeaderViewsCount()
ジョン

2
これが正しい答えかどうかはわかりません。@Ian Warwickが正しいものを投稿しましたが、少し遅れると思います。
sidon 2013年

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の「装飾」アダプターを使用してください。


このIMOは+1の方法です。提供するアダプターは、ヘッダーを提供するときにインデックスオフセットを考慮に入れる別のアダプターでラップされます。このためのこのコードは、これを使用しています。これは、このページの他の場所で@Rameshによって提供されています(+1あなたにも!)
Dori

5

これに対する1つの解決策は、IDをインデックスにマップすることです。基本的に、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とPhilippの答え​​を改善します、私たちはこのようなもので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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.