RecyclerView 通用Adapter添加头部、尾部 参考ListView的源码实现(一)

改进版:RecyclerView 通用Adapter添加头部、尾部 参考ListView的源码实现(二)
首先我们看下以前的ListView是如何实现addHeaderView、addFooterView
1.先看ListView.setAdapter(ListAdapter adapter) 方法
这里写图片描述

2.再看addHeaderView、addFooterView方法
这里写图片描述
以上2个方法中都用到了wrapHeaderListAdapterInternal方法,见下图
这里写图片描述
现在我们可以看出最终实现添加头部、尾部View,原来是靠HeaderViewListAdapter(包装后的Adapter)。
贴一下源码:

package android.widget;

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;

/**
 * ListAdapter used when a ListView has header views. This ListAdapter
 * wraps another one and also keeps track of the header views and their
 * associated data objects.
 *<p>This is intended as a base class; you will probably not need to
 * use this class directly in your own code.
 */
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {

    private final ListAdapter mAdapter;

    // These two ArrayList are assumed to NOT be null.
    // They are indeed created when declared in ListView and then shared.
    ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
    ArrayList<ListView.FixedViewInfo> mFooterViewInfos;

    // Used as a placeholder in case the provided info views are indeed null.
    // Currently only used by some CTS tests, which may be removed.
    static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
        new ArrayList<ListView.FixedViewInfo>();

    boolean mAreAllFixedViewsSelectable;

    private final boolean mIsFilterable;

    public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
                                 ArrayList<ListView.FixedViewInfo> footerViewInfos,
                                 ListAdapter adapter) {
        mAdapter = adapter;
        mIsFilterable = adapter instanceof Filterable;

        if (headerViewInfos == null) {
            mHeaderViewInfos = EMPTY_INFO_LIST;
        } else {
            mHeaderViewInfos = headerViewInfos;
        }

        if (footerViewInfos == null) {
            mFooterViewInfos = EMPTY_INFO_LIST;
        } else {
            mFooterViewInfos = footerViewInfos;
        }

        mAreAllFixedViewsSelectable =
                areAllListInfosSelectable(mHeaderViewInfos)
                && areAllListInfosSelectable(mFooterViewInfos);
    }

    public int getHeadersCount() {
        return mHeaderViewInfos.size();
    }

    public int getFootersCount() {
        return mFooterViewInfos.size();
    }

    public boolean isEmpty() {
        return mAdapter == null || mAdapter.isEmpty();
    }

    private boolean areAllListInfosSelectable(ArrayList<ListView.FixedViewInfo> infos) {
        if (infos != null) {
            for (ListView.FixedViewInfo info : infos) {
                if (!info.isSelectable) {
                    return false;
                }
            }
        }
        return true;
    }

    public boolean removeHeader(View v) {
        for (int i = 0; i < mHeaderViewInfos.size(); i++) {
            ListView.FixedViewInfo info = mHeaderViewInfos.get(i);
            if (info.view == v) {
                mHeaderViewInfos.remove(i);

                mAreAllFixedViewsSelectable =
                        areAllListInfosSelectable(mHeaderViewInfos)
                        && areAllListInfosSelectable(mFooterViewInfos);

                return true;
            }
        }

        return false;
    }

    public boolean removeFooter(View v) {
        for (int i = 0; i < mFooterViewInfos.size(); i++) {
            ListView.FixedViewInfo info = mFooterViewInfos.get(i);
            if (info.view == v) {
                mFooterViewInfos.remove(i);

                mAreAllFixedViewsSelectable =
                        areAllListInfosSelectable(mHeaderViewInfos)
                        && areAllListInfosSelectable(mFooterViewInfos);

                return true;
            }
        }

        return false;
    }

    public int getCount() {
        if (mAdapter != null) {
            return getFootersCount() + getHeadersCount() + mAdapter.getCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }

    public boolean areAllItemsEnabled() {
        if (mAdapter != null) {
            return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
        } else {
            return true;
        }
    }

    public boolean isEnabled(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).isSelectable;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.isEnabled(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
    }

    public Object getItem(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).data;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItem(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).data;
    }

    public long getItemId(int position) {
        int numHeaders = getHeadersCount();
        if (mAdapter != null && position >= numHeaders) {
            int adjPosition = position - numHeaders;
            int adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemId(adjPosition);
            }
        }
        return -1;
    }

    public boolean hasStableIds() {
        if (mAdapter != null) {
            return mAdapter.hasStableIds();
        }
        return false;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).view;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getView(adjPosition, convertView, parent);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).view;
    }

    public int getItemViewType(int position) {
        int numHeaders = getHeadersCount();
        if (mAdapter != null && position >= numHeaders) {
            int adjPosition = position - numHeaders;
            int adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }

        return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
    }

    public int getViewTypeCount() {
        if (mAdapter != null) {
            return mAdapter.getViewTypeCount();
        }
        return 1;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        if (mAdapter != null) {
            mAdapter.registerDataSetObserver(observer);
        }
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(observer);
        }
    }

    public Filter getFilter() {
        if (mIsFilterable) {
            return ((Filterable) mAdapter).getFilter();
        }
        return null;
    }

    public ListAdapter getWrappedAdapter() {
        return mAdapter;
    }
}


我们只需重点看 
getCount()
getItem()
getView()
getItemViewType()
getViewTypeCount()
这些方法的实现,上面的代码很简单应该都能看得懂,主要原理就是封装、化零为整思想,不关心未来入参的Adapter是怎样的,把它看做基类Adapter的一员,根据postion来智能地调用。

那么现在都是用RecyclerView来替代ListView了,但是RecyclerView本身是没提供addHeaderView、addFooterView方法,因为它是一个开放性、扩展性强的组件,更多的需要自定义实现。

附上源码
public class ListViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_view);
        RecyclerView recyclerView = new RecyclerView(this);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        InnerAdapter innerAdapter = new InnerAdapter();
        RecyclerBaseAdapter baseAdapter = new RecyclerBaseAdapter(innerAdapter);
        baseAdapter.setHeaderAdapter(new HeaderAdapter());
        baseAdapter.setFooterAdapter(new FooterAdapter());
        recyclerView.setAdapter(baseAdapter);
        addContentView(recyclerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    }


    class HeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new HeadViewHoloder(LayoutInflater.from(ListViewActivity.this).inflate(android.R.layout.simple_list_item_1, null, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            HeadViewHoloder holoder_ = (HeadViewHoloder) holder;
            ((TextView) holoder_.itemView).setText("我是头部" + position);
        }

        @Override
        public int getItemCount() {
            return 2;
        }


        class HeadViewHoloder extends RecyclerView.ViewHolder {

            public HeadViewHoloder(View itemView) {
                super(itemView);
            }
        }
    }

    class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new InnerViewHoloder(LayoutInflater.from(ListViewActivity.this).inflate(android.R.layout.simple_list_item_1, null, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            InnerViewHoloder holoder_ = (InnerViewHoloder) holder;
            ((TextView) holoder_.itemView).setText("我是正常Item" + position);
        }

        @Override
        public int getItemCount() {
            return 8;
        }


        class InnerViewHoloder extends RecyclerView.ViewHolder {

            public InnerViewHoloder(View itemView) {
                super(itemView);
            }
        }
    }


    class FooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new FooterViewHoloder(LayoutInflater.from(ListViewActivity.this).inflate(android.R.layout.simple_list_item_1, null, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            FooterViewHoloder holoder_ = (FooterViewHoloder) holder;
            ((TextView) holoder_.itemView).setText("我是尾部" + position);
        }

        @Override
        public int getItemCount() {
            return 3;
        }


        class FooterViewHoloder extends RecyclerView.ViewHolder {

            public FooterViewHoloder(View itemView) {
                super(itemView);
            }
        }
    }


    class RecyclerBaseAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private RecyclerView.Adapter mInnerAdapter;
        private RecyclerView.Adapter headerAdapter;
        private RecyclerView.Adapter footerAdapter;
        public static final int ITEM_TYPE_FOOTER = Integer.MAX_VALUE - 2;
        public static final int ITEM_TYPE_HEAD = Integer.MAX_VALUE - 1;

        public boolean isHasHeader() {
            return headerAdapter != null;
        }

        public boolean isHasFooter() {
            return footerAdapter != null;
        }

        public void setHeaderAdapter(RecyclerView.Adapter hasHeader) {
            this.headerAdapter = hasHeader;
        }

        public void setFooterAdapter(RecyclerView.Adapter footerAdapter) {
            this.footerAdapter = footerAdapter;
        }

        public RecyclerBaseAdapter(RecyclerView.Adapter mInnerAdapter) {
            this.mInnerAdapter = mInnerAdapter;
        }

        private boolean isHeaderViewType(int position) {
            return isHasHeader() && position <headerAdapter.getItemCount();
        }

        private boolean isFooterViewType(int position) {
            return isHasFooter() && (position >= mInnerAdapter.getItemCount() + (isHasHeader() ? headerAdapter.getItemCount() : 0));
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            if (viewType == ITEM_TYPE_HEAD) {
                return headerAdapter.onCreateViewHolder(parent, viewType);
            } else if (viewType == ITEM_TYPE_FOOTER) {
                return footerAdapter.onCreateViewHolder(parent, viewType);
            } else {
                return mInnerAdapter.onCreateViewHolder(parent, viewType);
            }
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

            switch (getItemViewType(position)) {
                case ITEM_TYPE_HEAD:
                    headerAdapter.onBindViewHolder(holder, position);
                    break;
                case ITEM_TYPE_FOOTER:
                    footerAdapter.onBindViewHolder(holder, position - mInnerAdapter.getItemCount() - (isHasHeader() ? headerAdapter.getItemCount() : 0));
                    break;
                default:
                    mInnerAdapter.onBindViewHolder(holder, position - (isHasHeader() ? headerAdapter.getItemCount() : 0));
                    break;
            }

        }

        @Override
        public int getItemCount() {
            return mInnerAdapter.getItemCount() + (isHasFooter() ? footerAdapter.getItemCount() : 0) + (isHasHeader() ? headerAdapter.getItemCount() : 0);
        }

        @Override
        public int getItemViewType(int position) {
            if (isHeaderViewType(position)) {
                return ITEM_TYPE_HEAD;
            } else if (isFooterViewType(position)) {
                return ITEM_TYPE_FOOTER;
            }
            return this.mInnerAdapter.getItemViewType(position - (isHasHeader() ? headerAdapter.getItemCount() : 0));
        }


    }
}
RecyclerBaseAdapter 就是根据getItemViewType实现的通用Adapter,这样就可以愉快地添加头部、尾部了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值