您的位置:首页 > 其它

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

2017-03-08 21:59 435 查看
 
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的必杀技。讲解完毕,谢谢!
附图片:
[align=left] [/align]
[align=left] [/align]
[align=left] [/align]
[align=left] [/align]
附demo如下:http://download.csdn.net/detail/oushangfeng123/8993489
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐