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
Dori

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

        }
    });

นี่น่าจะเป็นคำตอบที่ดีที่สุดฉันไม่สนใจเรื่องส่วนหัวฉันสนใจรายการ
Ninja

ผมคิดว่าวิธีนี้ไม่ได้ผลสำหรับระบบปฏิบัติการล่าสุด 7.0
หม่า

27

หากคุณเพิ่มส่วนหัวให้ListViewจะกลายเป็นรายการแรกในรายการ คุณสามารถชดเชยนี้โดยเอาชนะgetCount()เพื่อกลับไปหนึ่งรายการน้อยลง แต่ให้แน่ใจว่าคุณจัดการgetItem(), getItemId()และอื่น ๆ เป็นส่วนหัวจะเป็นรายการที่อยู่ในตำแหน่งที่ 0


6
การแทนที่ getCount () เพื่อส่งคืนหนึ่งรายการที่น้อยกว่านั้นไม่ได้ผลเพราะฉันพลาดรายการสุดท้ายของรายการ หากมีเพียง 1 รายการในรายการจะไม่มีการเรียก getView () นอกจากนี้อะแดปเตอร์ยังแยกออกจาก listview และไม่ทราบว่ามีการเพิ่มส่วนหัวใน listview หรือไม่
d1rk

2
ใน ListItemClick ตั้งค่า position = ตำแหน่ง - 1 หากมีส่วนหัวแนบมาฉันคิดว่านั่นคือสิ่งที่ฉันทำเมื่อฉันเผชิญกับปัญหานี้มันไม่เรียบร้อยมาก แต่เป็นวิธีเดียวที่ฉันคิดได้
akshaydashrath

3
ฉันเดาว่าวิธีที่ง่ายที่สุดคือตั้ง position = position- (จำนวน headerviews ที่เพิ่มเข้ามา) ใน OnItemClickListener ตามที่คุณแนะนำ ฉันเปลี่ยนอะแดปเตอร์เพื่อจัดการส่วนหัวของตัวเองดังนั้นฉันจึงไม่ต้องเรียก addHeaderView ใน listview แม้ว่าอะแดปเตอร์จะซับซ้อนกว่าเล็กน้อย
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
โดยปกติจะต้องมีการแคสต์เนื่องจากรายการที่ส่งคืนเป็นเพียง "วัตถุ"
นักพัฒนา Android

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.