Android RecyclerView使用详解四

转载请注明:
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创建需要的几个核心:
LayoutManager(必须)
ItemDecoration (非必须)
Adapter(必须)
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的接口都摒弃掉了,上述接口是可以去复写的。从这些接口看,我们可以发现,一般情况,我们需要复写的接口不多,大致是如下几个:
onCreateViewHolder
onBindViewHolder
getItemCount
getItemId

当然,如果你需要实现复杂的功能,可能还需要如下接口:
getItemViewType(定义当前item的类型)
onViewRecycled(当前item被回收时调用,可用来释放绑定在view上的大数据,比方说Bitmap)
……(太多。。)

常用的接口,在前面几篇里已经都讲解过,这里重点讲下getItemViewType。

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

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

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

鉴于此,我选择第二个方案(其实,你去看ListView的代码,你会发现,它添加header和footer的方式也是通过装饰模式的)。先来看看,我实现的添加headerView和footerView之后的效果:
Android RecyclerView使用详解四_第1张图片
这里添加的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!

你可能感兴趣的:(Android控件)