ฉันมีปัญหาเดียวกันกับ Lollipop และสร้างสองวิธีในการห่อRecyclerviewอะแดปเตอร์ อันหนึ่งค่อนข้างใช้งานง่าย แต่ฉันไม่แน่ใจว่ามันจะทำงานอย่างไรกับชุดข้อมูลที่เปลี่ยนไป เนื่องจากมันห่ออะแดปเตอร์ของคุณและคุณต้องตรวจสอบให้แน่ใจว่าได้เรียกใช้เมธอดเช่นnotifyDataSetChangedบนอะแด็ปเตอร์วัตถุที่ถูกต้อง
อื่น ๆ ไม่ควรมีปัญหาดังกล่าว เพียงแค่ปล่อยให้อะแดปเตอร์ปกติของคุณขยายคลาสใช้วิธีนามธรรมและคุณควรเตรียมตัวให้พร้อม และนี่คือ:
จิสต์
HeaderRecyclerViewAdapterV1
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
/**
 * Created by sebnapi on 08.11.14.
 * <p/>
 * This is a Plug-and-Play Approach for adding a Header or Footer to
 * a RecyclerView backed list
 * <p/>
 * Just wrap your regular adapter like this
 * <p/>
 * new HeaderRecyclerViewAdapterV1(new RegularAdapter())
 * <p/>
 * Let RegularAdapter implement HeaderRecyclerView, FooterRecyclerView or both
 * and you are ready to go.
 * <p/>
 * I'm absolutely not sure how this will behave with changes in the dataset.
 * You can always wrap a fresh adapter and make sure to not change the old one or
 * use my other approach.
 * <p/>
 * With the other approach you need to let your Adapter extend HeaderRecyclerViewAdapterV2
 * (and therefore change potentially more code) but possible omit these shortcomings.
 * <p/>
 * TOTALLY UNTESTED - USE WITH CARE - HAVE FUN :)
 */
public class HeaderRecyclerViewAdapterV1 extends RecyclerView.Adapter {
    private static final int TYPE_HEADER = Integer.MIN_VALUE;
    private static final int TYPE_FOOTER = Integer.MIN_VALUE + 1;
    private static final int TYPE_ADAPTEE_OFFSET = 2;
    private final RecyclerView.Adapter mAdaptee;
    public HeaderRecyclerViewAdapterV1(RecyclerView.Adapter adaptee) {
        mAdaptee = adaptee;
    }
    public RecyclerView.Adapter getAdaptee() {
        return mAdaptee;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HEADER && mAdaptee instanceof HeaderRecyclerView) {
            return ((HeaderRecyclerView) mAdaptee).onCreateHeaderViewHolder(parent, viewType);
        } else if (viewType == TYPE_FOOTER && mAdaptee instanceof FooterRecyclerView) {
            return ((FooterRecyclerView) mAdaptee).onCreateFooterViewHolder(parent, viewType);
        }
        return mAdaptee.onCreateViewHolder(parent, viewType - TYPE_ADAPTEE_OFFSET);
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (position == 0 && holder.getItemViewType() == TYPE_HEADER && useHeader()) {
            ((HeaderRecyclerView) mAdaptee).onBindHeaderView(holder, position);
        } else if (position == mAdaptee.getItemCount() && holder.getItemViewType() == TYPE_FOOTER && useFooter()) {
            ((FooterRecyclerView) mAdaptee).onBindFooterView(holder, position);
        } else {
            mAdaptee.onBindViewHolder(holder, position - (useHeader() ? 1 : 0));
        }
    }
    @Override
    public int getItemCount() {
        int itemCount = mAdaptee.getItemCount();
        if (useHeader()) {
            itemCount += 1;
        }
        if (useFooter()) {
            itemCount += 1;
        }
        return itemCount;
    }
    private boolean useHeader() {
        if (mAdaptee instanceof HeaderRecyclerView) {
            return true;
        }
        return false;
    }
    private boolean useFooter() {
        if (mAdaptee instanceof FooterRecyclerView) {
            return true;
        }
        return false;
    }
    @Override
    public int getItemViewType(int position) {
        if (position == 0 && useHeader()) {
            return TYPE_HEADER;
        }
        if (position == mAdaptee.getItemCount() && useFooter()) {
            return TYPE_FOOTER;
        }
        if (mAdaptee.getItemCount() >= Integer.MAX_VALUE - TYPE_ADAPTEE_OFFSET) {
            new IllegalStateException("HeaderRecyclerViewAdapter offsets your BasicItemType by " + TYPE_ADAPTEE_OFFSET + ".");
        }
        return mAdaptee.getItemViewType(position) + TYPE_ADAPTEE_OFFSET;
    }
    public static interface HeaderRecyclerView {
        public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent, int viewType);
        public void onBindHeaderView(RecyclerView.ViewHolder holder, int position);
    }
    public static interface FooterRecyclerView {
        public RecyclerView.ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType);
        public void onBindFooterView(RecyclerView.ViewHolder holder, int position);
    }
}
HeaderRecyclerViewAdapterV2
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
/**
 * Created by sebnapi on 08.11.14.
 * <p/>
 * If you extend this Adapter you are able to add a Header, a Footer or both
 * by a similar ViewHolder pattern as in RecyclerView.
 * <p/>
 * If you want to omit changes to your class hierarchy you can try the Plug-and-Play
 * approach HeaderRecyclerViewAdapterV1.
 * <p/>
 * Don't override (Be careful while overriding)
 * - onCreateViewHolder
 * - onBindViewHolder
 * - getItemCount
 * - getItemViewType
 * <p/>
 * You need to override the abstract methods introduced by this class. This class
 * is not using generics as RecyclerView.Adapter make yourself sure to cast right.
 * <p/>
 * TOTALLY UNTESTED - USE WITH CARE - HAVE FUN :)
 */
public abstract class HeaderRecyclerViewAdapterV2 extends RecyclerView.Adapter {
    private static final int TYPE_HEADER = Integer.MIN_VALUE;
    private static final int TYPE_FOOTER = Integer.MIN_VALUE + 1;
    private static final int TYPE_ADAPTEE_OFFSET = 2;
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HEADER) {
            return onCreateHeaderViewHolder(parent, viewType);
        } else if (viewType == TYPE_FOOTER) {
            return onCreateFooterViewHolder(parent, viewType);
        }
        return onCreateBasicItemViewHolder(parent, viewType - TYPE_ADAPTEE_OFFSET);
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (position == 0 && holder.getItemViewType() == TYPE_HEADER) {
            onBindHeaderView(holder, position);
        } else if (position == getBasicItemCount() && holder.getItemViewType() == TYPE_FOOTER) {
            onBindFooterView(holder, position);
        } else {
            onBindBasicItemView(holder, position - (useHeader() ? 1 : 0));
        }
    }
    @Override
    public int getItemCount() {
        int itemCount = getBasicItemCount();
        if (useHeader()) {
            itemCount += 1;
        }
        if (useFooter()) {
            itemCount += 1;
        }
        return itemCount;
    }
    @Override
    public int getItemViewType(int position) {
        if (position == 0 && useHeader()) {
            return TYPE_HEADER;
        }
        if (position == getBasicItemCount() && useFooter()) {
            return TYPE_FOOTER;
        }
        if (getBasicItemType(position) >= Integer.MAX_VALUE - TYPE_ADAPTEE_OFFSET) {
            new IllegalStateException("HeaderRecyclerViewAdapter offsets your BasicItemType by " + TYPE_ADAPTEE_OFFSET + ".");
        }
        return getBasicItemType(position) + TYPE_ADAPTEE_OFFSET;
    }
    public abstract boolean useHeader();
    public abstract RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent, int viewType);
    public abstract void onBindHeaderView(RecyclerView.ViewHolder holder, int position);
    public abstract boolean useFooter();
    public abstract RecyclerView.ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType);
    public abstract void onBindFooterView(RecyclerView.ViewHolder holder, int position);
    public abstract RecyclerView.ViewHolder onCreateBasicItemViewHolder(ViewGroup parent, int viewType);
    public abstract void onBindBasicItemView(RecyclerView.ViewHolder holder, int position);
    public abstract int getBasicItemCount();
    /**
     * make sure you don't use [Integer.MAX_VALUE-1, Integer.MAX_VALUE] as BasicItemViewType
     *
     * @param position
     * @return
     */
    public abstract int getBasicItemType(int position);
}
คำติชมและส้อมชื่นชม ฉันจะใช้HeaderRecyclerViewAdapterV2ด้วยตัวของฉันเองและพัฒนาทดสอบและโพสต์การเปลี่ยนแปลงในอนาคต
แก้ไข : @OvidiuLatcu ใช่ฉันมีปัญหาบางอย่าง อันที่จริงฉันหยุดการหักล้างส่วนหัวโดยปริยายposition - (useHeader() ? 1 : 0)และสร้างวิธีการสาธารณะint offsetPosition(int position)สำหรับมันแทน เพราะถ้าคุณตั้งค่าเป็นOnItemTouchListenerRecyclerview คุณสามารถสกัดกั้นการสัมผัสรับพิกัด x, y ของการสัมผัสค้นหาตามมุมมองเด็กจากนั้นโทรrecyclerView.getChildPosition(...)และคุณจะได้รับตำแหน่งที่ไม่หักล้างในอะแดปเตอร์เสมอ! นี่เป็นคำย่อใน RecyclerView Code ฉันไม่เห็นวิธีง่ายๆในการเอาชนะสิ่งนี้ นี่คือเหตุผลที่ตอนนี้ฉันหักล้างตำแหน่งที่ชัดเจนเมื่อฉันต้องการด้วยรหัสของฉันเอง