Android RecyclerView使用详解四

来源:互联网 发布:新疆人 知乎 编辑:程序博客网 时间:2024/04/30 05:51

转载请注明:
http://blog.csdn.net/sinat_30276961/article/details/50365513
上一篇介绍了RecyclerView自定义分隔图的代码绘制方式,本篇将在上篇的基础上讲解RecyclerView的header和footer的添加和设定,并且讲完header和footer,RecyclerView的基础内容就讲完了。

ok,废话少说。我们都知道,在ListView里添加header和footer是一件再简单不过的事情,秒秒钟搞定。那么在RecyclerView里添加呢?
在前面几篇里,我已经讲过了,RecyclerView的大部分功能都分离出来了,需要我们自己去复写,然后添加进去。虽然增加了麻烦度,但是带来的是灵活和无限的创造性。所以,header和footer的添加也是需要我们自己去代码设定加进去的。

我们再回忆一下RecyclerView创建需要的几个核心:
1. LayoutManager(必须)
2. ItemDecoration (非必须)
3. Adapter(必须)
4. ItemAnimator (非必须)

那么,header和footer该怎么加进去呢?
我们先来回忆一下RecyclerView.Adapter里包含的接口:

        public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);        public abstract void onBindViewHolder(VH holder, int position);        public int getItemViewType(int position) {            return 0;        }        public void setHasStableIds(boolean hasStableIds) {            if (hasObservers()) {                throw new IllegalStateException("Cannot change whether this adapter has " +                        "stable IDs while the adapter has registered observers.");            }            mHasStableIds = hasStableIds;        }        public long getItemId(int position) {            return NO_ID;        }        public abstract int getItemCount();        public void onViewRecycled(VH holder) {        }        public boolean onFailedToRecycleView(VH holder) {            return false;        }        public void onViewAttachedToWindow(VH holder) {        }        public void onViewDetachedFromWindow(VH holder) {        }        public void registerAdapterDataObserver(AdapterDataObserver observer) {            mObservable.registerObserver(observer);        }        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {            mObservable.unregisterObserver(observer);        }        public void onAttachedToRecyclerView(RecyclerView recyclerView) {        }        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {        }

我把final的接口都摒弃掉了,上述接口是可以去复写的。从这些接口看,我们可以发现,一般情况,我们需要复写的接口不多,大致是如下几个:
1. onCreateViewHolder
2. onBindViewHolder
3. getItemCount
4. getItemId
当然,如果你需要实现复杂的功能,可能还需要如下接口:
1. getItemViewType(定义当前item的类型)
2. onViewRecycled(当前item被回收时调用,可用来释放绑定在view上的大数据,比方说Bitmap)
3. ……(太多。。)

常用的接口,在前面几篇里已经都讲解过,这里重点讲下getItemViewType。
为啥要说这个接口呢?其实要实现在RecyclerView里添加headerView和footerView,这个接口是必不可少的。
getItemViewType是用来自己设定不同item的类型。既然如此,我们可以把header和footer看成是不同于一般item的类型不就行了。然后根据不同的viewType,我创建不同的view,也即是说,还需要修改
1. onCreateViewHolder(创建不同view)
2. onBindViewHolder(根据不同view,绑定不同数据)
3. getItemCount(header和footer不应该在此数量里)
4. getItemId(header占了index=0这个位置,所以需要调整)

ok,基本思路有了,现在想下方案。根据上述理念,我们目前能很容易想到的有两套方案:
1. 在原先自己写的adapter里根据需要添加上header和footer。
2. 通过装饰模式,在新的adapter里添加header和footer。

第一个方案,可行。
But!
要修改原来的代码,而且新改出来的adapter复用性差。
第二个方案,可行。
And!
不需要改动原来的adapter,复用性大大的提高。

鉴于此,我选择第二个方案(其实,你去看ListView的代码,你会发现,它添加header和footer的方式也是通过装饰模式的)。先来看看,我实现的添加headerView和footerView之后的效果:
这里写图片描述

这里添加的header和footer很简单,就是一个TextView。

ok,接下去,就是代码部分。我先贴出Adapter的代码:

public class HeaderRecyclerViewAdapter extends RecyclerView.Adapter{    public static final int ITEM_VIEW_TYPE_HEADER = -2;    public static final int ITEM_VIEW_TYPE_FOOTER = -3;    public static final int ITEM_VIEW_TYPE_ITEM = 0;    private RecyclerView.Adapter mAdapter;    private View mHeaderView;    private View mFooterView;    public HeaderRecyclerViewAdapter(View headerView, View footerView, RecyclerView.Adapter adapter) {        mHeaderView = headerView;        mFooterView = footerView;        mAdapter = adapter;    }    public RecyclerView.Adapter getWrappedAdapter() {        return mAdapter;    }    public boolean hasHeaderView() {        return mHeaderView != null;    }    public boolean hasFooterView() {        return mFooterView != null;    }    public int headerViewHeight() {        int height = 0;        if (mHeaderView != null) {            height = mHeaderView.getLayoutParams().height;        }        return height;    }    public int footerViewHeight() {        int height = 0;        if (mFooterView != null) {            height = mFooterView.getLayoutParams().height;        }        return height;    }    @Override    public int getItemViewType(int position) {        if (mHeaderView != null) {            if (position == 0) {                return ITEM_VIEW_TYPE_HEADER;            } else {                final int adjPosition = position - 1;                int adapterCount = 0;                if (mAdapter != null) {                    adapterCount = mAdapter.getItemCount();                    if (adjPosition < adapterCount) {                        return ITEM_VIEW_TYPE_ITEM;                    }                }            }        } else {            int adapterCount = 0;            if (mAdapter != null) {                adapterCount = mAdapter.getItemCount();                if (position < adapterCount) {                    return ITEM_VIEW_TYPE_ITEM;                }            }        }        return ITEM_VIEW_TYPE_FOOTER;    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == ITEM_VIEW_TYPE_HEADER) {            return new HeaderViewHolder(mHeaderView);        } else if (viewType == ITEM_VIEW_TYPE_FOOTER) {            return new HeaderViewHolder(mFooterView);        } else {            return mAdapter.onCreateViewHolder(parent, viewType);        }    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        final int viewType = getItemViewType(position);        if (viewType == ITEM_VIEW_TYPE_HEADER || viewType == ITEM_VIEW_TYPE_FOOTER) {            return;        } else {            int adjPosition = position;            if (mHeaderView != null) {                adjPosition--;            }            mAdapter.onBindViewHolder(holder, adjPosition);        }    }    @Override    public int getItemCount() {        if (mAdapter != null) {            return (mHeaderView == null ? 0 : 1)                    + (mFooterView == null ? 0 : 1)                    + mAdapter.getItemCount();        } else {            return (mHeaderView == null ? 0 : 1)                    + (mFooterView == null ? 0 : 1);        }    }    @Override    public long getItemId(int position) {        final boolean hasHeader = (mHeaderView != null);        final boolean hasFooter = (mFooterView != null);        int adapterCount = 0;        if (mAdapter != null) {            adapterCount = mAdapter.getItemCount();        }        if (hasHeader) {            if (position < adapterCount + 1) {                return position - 1;            } else {                return ITEM_VIEW_TYPE_FOOTER;            }        } else {            if (position < adapterCount) {                return position;            } else {                return ITEM_VIEW_TYPE_FOOTER;            }        }    }    static class HeaderViewHolder extends RecyclerView.ViewHolder {        public HeaderViewHolder(View itemView) {            super(itemView);        }    }

这部分代码其实不复杂,只要思路理清了,实现起来不麻烦。
第2、3、4行,定义了几种viewType。可以看到header我是从-2开始的。这是因为-1是无效的item(INVALID_TYPE = -1)。当然,你也可以从1开始定义。
第6行的mAdapter就是需要包装的原始adapter。
第8、9行,我定义了一个headerView和footerView。在ListView里,可以添加多个headerView和footerView,这里,我就只实现添加一个header和footer。如果要和ListView一样,那就把View改为List< View >。
第46-71行,复写了getItemViewType。在原始的position==0的位置,用来放置header;最后一个位置,用来放置footer。
第74-82行,复写了onCreateViewHolder。根据不同的viewType,我创建不同的view和viewholder。
第85-96行,复写了onBindViewHolder。如果viewType是header或者footer,就直接return。如果是一般的item,还需要调整下它的position。如果有header,原先的position还要-1。这样一来,在被装饰的原始adapter里,得到的position就已经排除了header的占位。

后面的代码和上述差不多,就是把header和footer的情况特殊处理,这里就不讲了。

接着,我贴下RecyclerView复写的代码:

public class HeaderRecyclerView extends RecyclerView{    private View mHeaderView;    private View mFooterView;    public HeaderRecyclerView(Context context) {        super(context);    }    public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    public void addHeaderView(View headerView) {        mHeaderView = headerView;    }    public void addFooterView(View footerView) {        mFooterView = footerView;    }    public void setAdapter(Adapter adapter) {        if (mHeaderView == null && mFooterView == null) {            super.setAdapter(adapter);        } else {            adapter = new HeaderRecyclerViewAdapter(mHeaderView, mFooterView, adapter);            super.setAdapter(adapter);        }    }    public void removeHeaderView() {        mHeaderView = null;    }    public void removeFooterView() {        mFooterView = null;    }}

上述代码就复写了setAdapter,代码很简单,不讲了。

接着是额外的部分,我把分隔图也重新改了一下,为了适应多了个header和footer。
先是HeaderLinearLayoutItemDecoration:

public class HeaderLinearLayoutItemDecoration extends RecyclerView.ItemDecoration{    final Context mContext;    final int mOrientation;    final Drawable mDividerDrawable;    int mDividerHeight;    private static final int[] ATTRS = new int[]{            android.R.attr.listDivider,            android.R.attr.dividerHeight    };    public HeaderLinearLayoutItemDecoration(Context context, int orientation) {        mContext = context;        mOrientation = orientation;        TypedArray ta = context.obtainStyledAttributes(ATTRS);        mDividerDrawable = ta.getDrawable(0);        mDividerHeight = ta.getDimensionPixelSize(1, 1);        ta.recycle();    }    public HeaderLinearLayoutItemDecoration(Context context, int orientation, int dividerHeight) {        mOrientation = orientation;        mContext = context;        mDividerHeight = dividerHeight;        TypedArray ta = context.obtainStyledAttributes(ATTRS);        mDividerDrawable = ta.getDrawable(0);        ta.recycle();    }    public HeaderLinearLayoutItemDecoration(Context context, int orientation, Drawable dividerDrawable, int dividerHeight) {        mContext = context;        mOrientation = orientation;        mDividerDrawable = dividerDrawable;        mDividerHeight = dividerHeight;    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        if (mOrientation == LinearLayoutManager.HORIZONTAL) {            drawHorizontal(c, parent);        } else {            drawVertical(c, parent);        }    }    private void drawHorizontal(Canvas c, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getHeight()-parent.getPaddingBottom();        final int count = parent.getChildCount();        for (int i = 0; i < count; i++) {            final View child = parent.getChildAt(i);            final int position = parent.getChildAdapterPosition(child);            final int viewType = parent.getAdapter().getItemViewType(position);            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                continue;            }            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            final int left = child.getRight()+params.rightMargin;            final int right = left+mDividerHeight;            mDividerDrawable.setBounds(left, top, right, bottom);            mDividerDrawable.draw(c);        }    }    private void drawVertical(Canvas c, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getWidth()-parent.getPaddingRight();        final int count = parent.getChildCount();        for (int i = 0; i < count; i++) {            final View child = parent.getChildAt(i);            final int position = parent.getChildAdapterPosition(child);            final int viewType = parent.getAdapter().getItemViewType(position);            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                continue;            }            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            final int top = child.getBottom()+params.bottomMargin;            final int bottom = top + mDividerHeight;            mDividerDrawable.setBounds(left, top, right, bottom);            mDividerDrawable.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        final int position = parent.getChildAdapterPosition(view);        final int viewType = parent.getAdapter().getItemViewType(position);        if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {            return;        }        if (mOrientation == LinearLayoutManager.VERTICAL) {            outRect.bottom = mDividerHeight;        } else {            outRect.right =  mDividerHeight;        }    }}

代码其实和原先的LinearLayoutItemDecoration几乎一样,唯一的区别在于:我在drawHorizontal、drawVertical和getItemOffsets里在遍历child时,多加了个判断,如果是header或者footer,就不画不偏移。

再贴出HeaderGridLayoutItemDecoration:

public class HeaderGridLayoutItemDecoration extends RecyclerView.ItemDecoration{    final Context mContext;    final Drawable mDividerDrawable;    int mDividerHeight;    private static final int[] ATTRS = new int[] {            android.R.attr.listDivider,            android.R.attr.dividerHeight    };    public HeaderGridLayoutItemDecoration(Context context) {        mContext = context;        // 从主题去获取属性键值        TypedArray ta = context.obtainStyledAttributes(ATTRS);        mDividerDrawable = ta.getDrawable(0);        mDividerHeight = ta.getDimensionPixelSize(1, 1);        ta.recycle();    }    public HeaderGridLayoutItemDecoration(Context context, int height) {        mContext = context;        // 从主题去获取属性键值        TypedArray ta = context.obtainStyledAttributes(ATTRS);        mDividerDrawable = ta.getDrawable(0);        mDividerHeight = height;        ta.recycle();    }    public HeaderGridLayoutItemDecoration(Context context, Drawable drawable) {        mContext = context;        mDividerDrawable = drawable;        TypedArray ta = context.obtainStyledAttributes(ATTRS);        mDividerHeight = ta.getDimensionPixelSize(1, 1);        ta.recycle();    }    public HeaderGridLayoutItemDecoration(Context context, Drawable drawable, int height) {        mContext = context;        mDividerDrawable = drawable;        mDividerHeight = height;    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();        final int spanCount = manager.getSpanCount();        drawHorizontal(c, parent, state, spanCount);        drawVertical(c, parent, state, spanCount);    }    private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {        final int count = parent.getChildCount();        // 确定有几行        final int rowCount = count/spanCount + (count%spanCount==0?0:1);        final int left = parent.getPaddingLeft();        final int right = parent.getWidth() - parent.getPaddingRight();        for (int i = 0; i < rowCount; i++) {            final View child = parent.getChildAt(i*spanCount);            final int position = parent.getChildAdapterPosition(child);            final int viewType = parent.getAdapter().getItemViewType(position);            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                continue;            }            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mDividerHeight;            mDividerDrawable.setBounds(left, top, right, bottom);            mDividerDrawable.draw(c);        }    }    private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {        final int count = parent.getChildCount();        for (int i = 0; i < count; i++) {            final View child = parent.getChildAt(i);            final int position = parent.getChildAdapterPosition(child);            final int viewType = parent.getAdapter().getItemViewType(position);            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                continue;            }            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            final int left = child.getRight() + params.rightMargin;            final int right = left + mDividerHeight;            final int top = child.getTop() - params.topMargin;            final int bottom = child.getBottom() + params.bottomMargin + mDividerHeight;            mDividerDrawable.setBounds(left, top, right, bottom);            mDividerDrawable.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();        final int spanCount = manager.getSpanCount();        final int position = parent.getChildAdapterPosition(view);        final int adjPosition = (int) parent.getAdapter().getItemId(position);        final int count = parent.getAdapter().getItemCount();        final int viewType = parent.getAdapter().getItemViewType(position);        if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {            return;        }        if ((adjPosition == count -1) && (adjPosition % spanCount) == (spanCount - 1)) {            // 最后一个,如果也是最右边,那么就不需要偏移        } else if (adjPosition >= (count - (count % spanCount))) {            // 最下面一行,只要右边偏移就行            outRect.right = mDividerHeight;        } else if ((adjPosition % spanCount) == (spanCount - 1)) {            // 最右边一列,只要下面偏移就行            outRect.bottom = mDividerHeight;        } else {            // 其他的话,右边和下面都要偏移            outRect.set(0, 0, mDividerHeight, mDividerHeight);        }    }}

这里,思路和HeaderLinearLayoutItemDecoration一样,就是在画和设置偏移的地方多加个header和footer的判断。
唯一不同的是,drawVertical和GridLayoutItemDecoration里的drawVertical不一样了。因为原先的实现方式是遍历span数量,并画spanCount数量的垂直drawable,并且是从屏幕最上方到屏幕最下方(parent.getPaddingTop和parent.getHeight() - parent.getPaddingBottom())。但是如果添加了header和footer,原先的方案就会使垂直drawable覆盖在header和footer上。并且如果是通过设置header和footer高度的偏移值来去掉header和footer那里的垂直drawable,也不好判断当前滑动位置是否包含header和footer,包含多少。所以,最好的方案是一个个item遍历画。

ok,到目前为止,所有需要的角色都已经讲完了。接着就是测试代码了:

public class AddHeaderViewTest extends ActionBarActivity {    HeaderRecyclerView mHeaderRecyclerView;    RecyclerViewAdapter mLinearLayoutAdapter;    HeaderLinearLayoutItemDecoration mLinearLayoutItemDecoration;    LinearLayoutManager mLinearLayoutManager;    GridRecyclerViewAdapter mGridLayoutAdapter;    HeaderGridLayoutItemDecoration mGridLayoutItemDecoration;    GridLayoutManager mGridLayoutManager;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_add_header_view_test);        mHeaderRecyclerView = (HeaderRecyclerView) findViewById(R.id.headerRecyclerView);        mLinearLayoutManager = new LinearLayoutManager(this);        mGridLayoutManager = new GridLayoutManager(this, 4);        // grid类型,需要复写这个方法        // 确定每个item的横跨span数        mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {            @Override            public int getSpanSize(int position) {                final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                    return mGridLayoutManager.getSpanCount();                } else {                    return 1;                }            }        });        mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);        mLinearLayoutItemDecoration = new HeaderLinearLayoutItemDecoration(this, LinearLayoutManager.VERTICAL, 4);        mGridLayoutItemDecoration = new HeaderGridLayoutItemDecoration(this, 18);        mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);        // 添加header        TextView headerView = new TextView(this);        headerView.setText("Header");        headerView.setTextColor(Color.GRAY);        headerView.setTextSize(18);        headerView.setGravity(Gravity.CENTER);        ViewGroup.LayoutParams headerParams = new ViewGroup.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                DensityUtil.dpToPx(60, getResources())        );        headerView.setLayoutParams(headerParams);        mHeaderRecyclerView.addHeaderView(headerView);        // 添加footer        TextView footerView = new TextView(this);        footerView.setText("Footer");        footerView.setTextColor(Color.GRAY);        footerView.setTextSize(18);        footerView.setGravity(Gravity.CENTER);        ViewGroup.LayoutParams footerParams = new ViewGroup.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                DensityUtil.dpToPx(60, getResources())        );        footerView.setLayoutParams(footerParams);        mHeaderRecyclerView.addFooterView(footerView);        mLinearLayoutAdapter = new RecyclerViewAdapter(this, R.layout.item_normal_recycler_view, 50);        mGridLayoutAdapter = new GridRecyclerViewAdapter(this, R.layout.item_recycler_view_grid, 100);        mLinearLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {            @Override            public void onItemClick(View view, int position) {                Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();            }        });        mGridLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {            @Override            public void onItemClick(View view, int position) {                Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();            }        });        mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_add_header_view_test, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        //noinspection SimplifiableIfStatement        if (id == R.id.action_switch) {            if (mHeaderRecyclerView.getLayoutManager() == mLinearLayoutManager) {                mHeaderRecyclerView.setLayoutManager(mGridLayoutManager);                mHeaderRecyclerView.removeItemDecoration(mLinearLayoutItemDecoration);                mHeaderRecyclerView.addItemDecoration(mGridLayoutItemDecoration);                mHeaderRecyclerView.setAdapter(mGridLayoutAdapter);            } else {                mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);                mHeaderRecyclerView.removeItemDecoration(mGridLayoutItemDecoration);                mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);                mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);            }            return true;        }        return super.onOptionsItemSelected(item);    }}

这部分代码和原先的差不多,唯一不同点在于布局文件里的RecyclerView要使用自定义的HeaderRecyclerView。
还有一个地方是:

        // grid类型,需要复写这个方法        // 确定每个item的横跨span数        mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {            @Override            public int getSpanSize(int position) {                final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {                    return mGridLayoutManager.getSpanCount();                } else {                    return 1;                }            }        });

对于GridLayoutManager,你需要通过setSpanSizeLookup复写getSpanSize这个接口。这个是用来确定每个item占据的span数量。默认情况下,返回的是1,也就是每个item占据1个span。
对于header和footer这两个item,每个都需要占据spanCount数量的span。

好了,关于RecyclerView添加headerView和footerView部分讲解完了。并且,RecyclerView的基础部分都讲解完了。

Have a good night!

1 0