参考:
RecyclerView有标题栏的分类列表 自定义列数(不同行设置不同个子项item)
Android图片转换类 1. Bitmap去色,转换为黑白的灰度图, 2. Bitmap图片加圆角效果
Glide变换
Class BitmapTransformation
因为要区分标题栏和内容栏,所以这两个item的布局是不一样的,不大可能使用同一个itemView。
然而从源代码里可以看到,一个ViewHolder只能绑定一个itemView,所以需要分成两个ViewHolder。
但是一个RecyclerView.Adapter里面只能跟一个AppAdapter.ViewHolder,所以要把这两个ViewHolder变成内部类写在一个ViewHolder里面。
public class ViewHolder extends RecyclerView.ViewHolder {
private static final int TYPE_TITLE = 0;
public TitleViewHolder titleViewHolder;
public ContentViewHolder contentViewHolder;
// 一定要写 而且不能改参数列表 也不能删掉super(itemView)
// 但是因为我们真正用到的构造函数不是这个 所以也就先摆在这里
public ViewHolder(View itemView) {
super(itemView);
}
// 相当于初始化了另外两个VieHolder的其中一个 因为一次onBindViewHolder只能绑定一个
public ViewHolder(View view, int type) {
this(view);
if (type == TYPE_TITLE) titleViewHolder = new TitleViewHolder(view);
else contentViewHolder = new ContentViewHolder(view);
}
public class TitleViewHolder extends RecyclerView.ViewHolder {
// 标题的布局 外面一层LinearLayout加里面一个TextView
@BindView(R.id.title)
TextView title;
public TitleViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public class ContentViewHolder extends RecyclerView.ViewHolder {
// 内容的布局 外面一层LinearLayout里面一个ImageView
@BindView(R.id.image)
ImageView image;
public ContentViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
由于这个RecyclerView是使用GridLayoutManager来完成的,所以如果是遇到标题的话,那标题应该是占满了一整行。
RecyclerView的部分源码
/**
* Called by RecyclerView when it starts observing this Adapter.
*
* Keep in mind that same adapter may be observed by multiple RecyclerViews.
*
* @param recyclerView The RecyclerView instance which started observing this adapter.
* @see #onDetachedFromRecyclerView(RecyclerView)
*/
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
}
所以需要重写onAttachedToRecyclerView
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
GridLayoutManager manager = (GridLayoutManager) recyclerView.getLayoutManager();
// 设置一个item占的空间
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int i) {
// 如果不是标题 那就站一格
// 如果是标题 那就占满正行
if (!mListItems.get(i).isTitle()) return 1;
else return NUM_COLUMNS;
}
});
}
因为创建ViewHolder的实例的时候需要判断是标题栏还是内容栏,在onCreateViewHolder
的时候会用上。
RecyclerView的部分源码
/**
* Return the view type of the item at position
for the purposes
* of view recycling.
*
* The default implementation of this method returns 0, making the assumption of
* a single view type for the adapter. Unlike ListView adapters, types need not
* be contiguous. Consider using id resources to uniquely identify item view types.
*
* @param position position to query
* @return integer value identifying the type of the view needed to represent the item at
* position
. Type codes need not be contiguous.
*/
public int getItemViewType(int position) {
return 0;
}
重写getItemViewType
。
@Override
public int getItemViewType(int position) {
if (mListItems.get(position).isTitle()) return VIEW_TYPE_TITLE;
else return VIEW_TYTPE_CONTENT;
}
前面在getItemViewType
的时候已经给ViewHolder分了类型。
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view;
ViewHolder viewHolder = null;
switch (viewType) {
case VIEW_TYPE_TITLE:
view = inflater.inflate(R.layout.adapter_title, null);
viewHolder = new ViewHolder(view, VIEW_TYPE_TITLE);
break;
case VIEW_TYTPE_CONTENT:
view = inflater.inflate(R.layout.adapter_content);
viewHolder = new ViewHolder(view, VIEW_TYTPE_CONTENT);
break;
default:
break;
}
return viewHolder;
}
创建完ViewHoder之后就要绑定每个ViewHolder里面的信息,例如TextView里面要写些什么字,ImageView里面要放张什么图,
要不要给每一个item加个点击事件或者自己写个别的回调。
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Item item = mListItems.get(position);
if (item.isTitle()) {
holder.titleViewHolder.title.setText(item.getTitle());
} else {
holder.contentViewHolder.image.setImageDrawable(item.getIcon());
holder.contentViewHolder.image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "you click this imageView", Toast.LENGTH_SHORT).show();
}
});
}
}
用回上面onBindViewHolder
的代码,不过这个时候的图片不是本地获取的,而是从网上下载的。
// 因为存储的时候是String类型的网址 所以必须转成Uri类型
Uri uri = Uri.parse(item.getUri());
// Glide有提供transform函数对获取的图片进行转换
// 如果直接从holder.contentViewHolder.image中获取图片的话 是null
Glide.with(mContext)
.load(uri)
.transform(new Adapter.ColorfulToGrey(mContext))
.into(holder.contentViewHolder.image);
灰度图的算法,从网上找的
// 官方推荐是继承BitmapTransformation来写
public class ColorfulToGrey extends BitmapTransformation {
private static final String ID = "com.example.demo.ColorfulToGrey";
public ColorfulToGrey(Context context) {
super(context);
}
@Override
protected Bitmap transform(BitmapPool bitmapPool, Bitmap bitmap, int i0, int i1) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
ColorMatrix ColorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
canvas.drawBitmap(bitmap, 0, 0, paint);
return result;
}
@Override
public String getId() {
return ID;
}
@Override
public int hashCode() {
return ID.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
return obj instanceof Adapter.ColorfulToGrey;
}
}