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

답변:


113

난 그냥이 문제를 가로 질러 와서 가장 좋은 방법은 사용하는 것 ListView.getItemAtPosition(position)대신 ListAdapter.getItem(position)은 AS ListView버전은 헤더, 즉를 차지한다 : -

대신 다음을 수행하십시오.

myListView.getItemAtPosition(position)

1
그래요! onItemClick당신을주는 parent이유. 사용할 수 있습니다parent.getItemAtPosition(position)
Brais Gabin 2013-06-12

3
@whuandroid 장식 / 래퍼 어댑터 솔루션을 사용하는 반면 이것은 실제로 저에게 효과적이지 않았습니다.
Dori

3
또한이 경우 항목을 캐스팅해야합니다.
njzk2

부모를 ListView로 캐스트하더라도 나를 위해 작동하지 않습니다. 위치를 제외하면됩니다 == 0 ...
PawelP 2014 년

나를 위해 작동하지 않습니다. 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);

        }
    });

이것이 최선의 대답이어야합니다. 헤더는 신경 쓰지 않고 목록 항목은 신경 쓰죠.
닌자

이 솔루션은 최신 OS 7.0에서 작동하지 않는다고 생각합니다
sha

27

ListView목록의 첫 번째 항목이 되는에 헤더를 추가하는 경우 . 를 재정 의하여 getCount()항목 하나를 적게 반환 하여이를 보완 할 수 있지만 헤더가 위치 0에있는 항목이므로 getItem(), getItemId()등 을 처리해야합니다 .


6
하나의 항목을 적게 반환하도록 getCount ()를 재정의하면 목록의 마지막 목록 항목을 놓치기 때문에 작동하지 않습니다. 목록에 항목이 1 개만 있으면 getView ()가 호출되지 않습니다. 또한 어댑터는 목록보기에서 분리되며 목록보기에 추가 된 헤더가 있는지 여부를 알 수 없습니다.
d1rk

2
ListItemClick 세트 위치 = 위치에서 - 헤더가 붙어있는 경우 1, 생각 나는, 매우 깔끔한되지를이 특정 문제에 직면하지만, 유일한 방법은 내가 생각할 때 내가 무슨 짓 이잖아
akshaydashrath

3
가장 쉬운 방법은 제안한대로 OnItemClickListener에서 position = position- (추가 된 headerviews 수)를 설정하는 것입니다. headerview 자체를 처리하도록 어댑터를 변경 했으므로 listview에서 addHeaderView를 호출 할 필요가 없습니다. 어댑터가 조금 더 복잡해졌지만.
d1rk

22
"추가 된 헤더 뷰 수"는 다음과 같이 얻을 수 있습니다.ListView.getHeaderViewsCount()
John

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
반환되는 항목이 "Object"일 뿐이므로 일반적으로 캐스팅이 필요합니다.
안드로이드 개발자

9

어댑터를 사용하지 말고 getAdapter의 '장식 된'어댑터를 사용하십시오.


+1이 IMO는 갈 길입니다. 제공하는 어댑터는 헤더를 제공 할 때 인덱스 오프셋을 고려하는 다른 어댑터로 래핑됩니다. 이 코드는 이것을 사용하고 있습니다. @Ramesh가이 페이지의 다른 곳에서 제공합니다 (당신에게도 +1!)
Dori

5

이에 대한 한 가지 해결책은 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);

답변 목록 아래에 있지만 정말 유용합니다. 이러한 변경 사항을 적용하지 않으면 파급 효과 등으로 헤더보기를 클릭 할 수 있습니다.
Scott Ferguson

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.