快速实现RecycleView的网格和瀑布流布局添加头部(尾部原理一样,故略之)

来源:互联网 发布:淘宝旧版本5.4.8 编辑:程序博客网 时间:2024/05/16 09:00

RecycleView高度的解耦,非常灵活,通过布局管理器LayoutManager控制其显示的布局;通过ItemDecoration控制Item间的间隔;通过ItemAnimator控制Item增删的动画;不过需要自己写接口实现点击、长按事件。它只管回收与复用View。
然后最坑爹的是没了addHeader和addFooter,需要自己实现(怨念中…),自己找开源的代码发现稍微有点繁琐,于是自己动手研究利用Manager的特性还有LayoutParams实
现了添加头尾等操作,接下来介绍GridLayoutManager和StaggeredGridLayoutManager怎么添加头部,LinearLayout太简单了就不介绍了。

①GridLayoutManager添加头部操作
网格布局配置:
关键在于继承GridLayoutManager.SpanSizeLookup实现HeaderSpanSizeLookup来处理指定位置占多少列的操作来实现添加头部

GridLayoutManager glm = new GridLayoutManager(this, 2);        glm.setSpanSizeLookup(new HeaderSpanSizeLookup(glm));        recyclerView.setLayoutManager(glm);        recyclerView.addItemDecoration(new SpacesItemDecoration(5));        recyclerView.setAdapter(new LayoutAdapter());

HeaderSpanSizeLookup 在getSpanSize方法这里通过position=0来设置该位置的view占满getSpanCount即我们设置的两列

    class HeaderSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {        private final GridLayoutManager layoutManager;        public HeaderSpanSizeLookup(GridLayoutManager layoutManager) {            this.layoutManager = layoutManager;        }        @Override        public int getSpanSize(int position) {            position = position == 0 ? layoutManager.getSpanCount() : 1;            return position;        }    }

LayoutAdapter 的实现跟瀑布流的大同小异,细节注释去看下面的瀑布流即可

class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.SimpleViewHolder> {        private static final int TYPE_HEADER = 1, TYPE_ITEM = 2;        class SimpleViewHolder extends RecyclerView.ViewHolder {            ImageView header;            ImageView item;            public SimpleViewHolder(View view) {                super(view);                header = (ImageView) view.findViewById(R.id.iv_header);                item = (ImageView) view.findViewById(R.id.iv_item);            }        }        @Override        public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = null;            switch (viewType) {                case TYPE_HEADER:                    view = LayoutInflater.from(GridLayoutManagerActivity.this).inflate(R.layout.header, parent, false);                    break;                case TYPE_ITEM:                    view = LayoutInflater.from(GridLayoutManagerActivity.this).inflate(R.layout.item, parent, false);                    break;            }            return new SimpleViewHolder(view);        }        int size[] = new int[2];        @Override        public void onBindViewHolder(final SimpleViewHolder holder, int position) {            switch (holder.getItemViewType()) {                case TYPE_HEADER:                    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) holder.header.getLayoutParams();                    size = getImageRealSize(R.drawable.ic_girls_banner);                    lp.width = metrics.widthPixels;                    lp.height = lp.width * size[1] / size[0];                    holder.header.setLayoutParams(lp);                    Glide.with(GridLayoutManagerActivity.this).                            load(R.drawable.ic_girls_banner).                            asBitmap().                            diskCacheStrategy(DiskCacheStrategy.ALL).                            into(new BitmapImageViewTarget(holder.header) {                                @Override                                public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {                                    super.onResourceReady(resource, glideAnimation);                                    Palette.from(resource).generate(new Palette.PaletteAsyncListener() {                                        @Override                                        public void onGenerated(Palette palette) {                                            ((CardView)holder.header.getParent()).setCardBackgroundColor(palette.getMutedColor(Color.parseColor("#ffffff")));                                        }                                    });                                }                            });                    break;                case TYPE_ITEM:                    final ViewGroup.LayoutParams lp1 = (ViewGroup.LayoutParams) holder.item.getLayoutParams();                    size = getImageRealSize(mItems.get(position - 1));                    lp1.width = metrics.widthPixels / 2;                    lp1.height = metrics.widthPixels / 2 * size[1] / size[0];                    holder.item.setLayoutParams(lp1);                    Glide.with(GridLayoutManagerActivity.this).                            load(mItems.get(position - 1)).                            asBitmap().                            diskCacheStrategy(DiskCacheStrategy.ALL).                            into(new BitmapImageViewTarget(holder.item) {                                @Override                                public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {                                    super.onResourceReady(resource, glideAnimation);                                    Palette.from(resource).generate(new Palette.PaletteAsyncListener() {                                        @Override                                        public void onGenerated(Palette palette) {                                            ((CardView) holder.item.getParent()).setCardBackgroundColor(palette.getMutedColor(Color.parseColor("#ffffff")));                                        }                                    });                                }                            });                    break;            }        }        @Override        public int getItemViewType(int position) {            return position = position == 0 ? TYPE_HEADER : TYPE_ITEM;        }        @Override        public int getItemCount() {            return mItems.size() + 1;        }    }

②StaggeredGridLayoutManager添加头部操作

首先按正常的配置配,这里我配的是两列,垂直

StaggeredGridLayoutManager sglm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);        recyclerView.setLayoutManager(sglm);        recyclerView.addItemDecoration(new SpacesItemDecoration(5));        recyclerView.setAdapter(new LayoutAdapter());

SpacesItemDecoration是继承ItemDecoration用来设间隔的

class SpacesItemDecoration extends RecyclerView.ItemDecoration {        private int space;        private StaggeredGridLayoutManager.LayoutParams lp;        public SpacesItemDecoration(int space) {            this.space = space;        }        @Override        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {            int position = parent.getChildAdapterPosition(view);            outRect.left = space;            outRect.right = space;            outRect.bottom = space;            if (position == 0) {            // 用于设第一个位置跟顶部的距离                outRect.top = space;            } else {                lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();                if (lp.getSpanIndex() == 0) {                // 用于设同行两个间隔间跟其距离左右屏幕间隔相同                    outRect.right = 0;                }            }        }    }

最关键的是Adapter的实现了,
头部是利用StaggeredGridLayoutManager.LayoutParams.setFullSpan(true)来实现占满两列的

class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.SimpleViewHolder> {// view的type:头部,内容        private static final int TYPE_HEADER = 1, TYPE_ITEM = 2;        class SimpleViewHolder extends RecyclerView.ViewHolder {        // 头部的控件            ImageView header;            CardView cardview;            // 内容的控件               ImageView item;            public SimpleViewHolder(View view) {                super(view);                header = (ImageView) view.findViewById(R.id.iv_header);                item = (ImageView) view.findViewById(R.id.iv_item);                cardview = (CardView) view.findViewById(R.id.cardview);            }        }        @Override        public int getItemViewType(int position) {        // 位置为0的话类型为头部,其余为内容            return position = position == 0 ? TYPE_HEADER : TYPE_ITEM;        }        @Override        public int getItemCount() {        // 加一是因为添加了头部            return mItems.size() + 1;        }        @Override        public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = null;            switch (viewType) {            // 根据类型填充不同布局                case TYPE_HEADER:                    view = LayoutInflater.from(MainActivity.this).inflate(R.layout.header, parent, false);                    break;                case TYPE_ITEM:                    view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, parent, false);                    break;            }            return new SimpleViewHolder(view);        }        int size[] = new int[2];        @Override        public void onBindViewHolder(final SimpleViewHolder holder, int position) {            switch (holder.getItemViewType()) {                case TYPE_HEADER:                // 根据view类型处理不同的操作                // 获取cardview的布局属性,记住这里要是布局的最外层的控件的布局属性,如果是里层的会报cast错误                StaggeredGridLayoutManager.LayoutParams clp = (StaggeredGridLayoutManager.LayoutParams) holder.cardview.getLayoutParams();                // 最最关键一步,设置当前view占满列数,这样就可以占据两列实现头部了                clp.setFullSpan(true);                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) holder.header.getLayoutParams();                // 获取资源图片宽高,用于等比例加载图片                size = getImageRealSize(R.drawable.ic_girls_banner);                // 宽度为屏幕宽度                lp.width = metrics.widthPixels;                // 等比例得到高度                lp.height = lp.width * size[1] / size[0];                holder.header.setLayoutParams(lp);                Glide.with(MainActivity.this).                     load(R.drawable.ic_girls_banner).                     asBitmap().                 diskCacheStrategy(DiskCacheStrategy.ALL).                  into(new BitmapImageViewTarget(holder.header) {                @Override                public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {                          super.onResourceReady(resource, glideAnimation);                           Palette.from(resource).generate(new Palette.PaletteAsyncListener() {                                        @Override                                        public void onGenerated(Palette palette) {                                            /*Palette这个类中提取以下突出的颜色:                                            Vibrant(有活力)                                            Vibrant dark(有活力 暗色)                                            Vibrant light(有活力 亮色)                                            Muted  (柔和)                                            Muted dark(柔和 暗色)                                            Muted light(柔和 亮色)*/                                            holder.cardview.setCardBackgroundColor(palette.getMutedColor(Color.parseColor("#ffffff")));                                        }                                    });                                }                            });                    break;                case TYPE_ITEM:                    final ViewGroup.LayoutParams lp1 = (ViewGroup.LayoutParams) holder.item.getLayoutParams();                    size = getImageRealSize(mItems.get(position - 1));                    lp1.width = metrics.widthPixels / 2;                    lp1.height = metrics.widthPixels / 2 * size[1] / size[0];                    holder.item.setLayoutParams(lp1);                    Glide.with(MainActivity.this).                            load(mItems.get(position - 1)).                            asBitmap().                            diskCacheStrategy(DiskCacheStrategy.ALL).                            into(new BitmapImageViewTarget(holder.item) {                                @Override                                public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {                                    super.onResourceReady(resource, glideAnimation);                                    Palette.from(resource).generate(new Palette.PaletteAsyncListener() {                                        @Override                                        public void onGenerated(Palette palette) {                                            ((CardView) holder.item.getParent()).setCardBackgroundColor(palette.getMutedColor(Color.parseColor("#ffffff")));                                        }                                    });                                }                            });                    break;            }        }    }

头部布局

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/cardview"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    app:cardCornerRadius="8dp"    app:cardElevation="5dp"    app:contentPadding="1dp">    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"        android:id="@+id/iv_header"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="#44000000">    </ImageView></android.support.v7.widget.CardView>

内容布局

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/cardview"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    app:cardCornerRadius="8dp"    app:cardElevation="5dp"    app:contentPadding="1dp">    <ImageView        android:id="@+id/iv_item"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="#44000000">    </ImageView></android.support.v7.widget.CardView>

由上可以看到,GridLayoutManager是通过GridLayoutManager.SpanSizeLookup来控制占的列数来实现头部添加的;
StaggeredGridLayoutManager是通过在Adapter的oncreateView那里判断ViewType为头部类型的时候,获取布局最外层控件的StaggeredGridLayoutManager.LayoutParams,调用StaggeredGridLayoutManager.LayoutParams.setFullSpan(true)来控制占的列数来实现头部添加的。

看完了是不是觉得so easy呢?只要掌握了这个,任意添加不同布局,控制占的不同列数,我们可以实现各种各样的需求,我想这就是RecycleView取代listview和gridview的必杀技。讲解完毕,谢谢!

附图片:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

附demo如下:
http://download.csdn.net/detail/oushangfeng123/8993489

0 0