https://blog.csdn.net/qq_20949825/article/details/52103395
使用RecyclerView和Glide实现图片瀑布流(防止错位)
最近正在学习Android的新控件RecyclerView,感觉这是一个自由度很高的控件,除了可以实现最基本的ListView,GridView的功能之外,还可以实现瀑布流的效果。 Android RecyclerView 使用完全解析 体验艺术般的控件,其中很详细的说明了如何去使用和订制RecyclerView,而这篇博客写的是我在使用RecyclerView与Glide实现瀑布流功能时遇到的坑。
首先贴出activity,布局代码
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
mDatas = new ArrayList<String>();
for (int i = 0 ; i < Images.imageUrls.length ; i++){
String data = Images.imageUrls[i];
mDatas.add(data);
}
}
private void initView() {
recyclerView = (RecyclerView) findViewById(R.id.rv);
//添加布局管理
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager);
//设置适配器
recyclerView.setAdapter(new RecycleAdapter(this,mDatas));
//设置item添加和删除的动画
// recyclerView.setItemAnimator();
//设置分隔线
// recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.syf.recyclerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
activity的布局很简单,其中只有一个recyclerview,activiy中的代码也是最基本的加载recyclerview的代码。
然后是adapter的代码
public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.MyViewHolder> {
private List<String> mDatas;
private Context context;
private LayoutInflater inflater;
private SparseArray<Integer> heightArray;
public RecycleAdapter(Context context , List<String> mDatas){
this.context = context;
this.mDatas = mDatas;
this.inflater = LayoutInflater.from(context);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
heightArray = new SparseArray<Integer>();
View itemView = inflater.inflate(R.layout.item_recycle,parent,false);
MyViewHolder viewHolder = new MyViewHolder(itemView);
return viewHolder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
Glide.with(context)
.load(mDatas.get(position))
.into(holder.iv);
}
@Override
public int getItemCount() {
return mDatas.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
ImageView iv;
public MyViewHolder(View itemView) {
super(itemView);
iv = (ImageView) itemView.findViewById(R.id.iv);
}
}
}
adapter中在onBindViewHolder中使用了Glide图片框架来加载图片。这样子一个最基本的瀑布流加载图片就实现了。但是这样加载出来的瀑布流在滑动的时候是会有图片的错位的。为了解决这个问题,需要如下几个步骤:
1.在activity中加入manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);这句代码,可以防止recyclerview在加载的过程中的item的错位。但是,加入了这句代码后,recyclerview的图片加载问题反而更大了,有时甚至会出现大片的空白,就像下图所示:
卧槽,那加这句代码干什么,还不如不加呢。先不要急,这句代码是防止item错位和位置变化的,但是图片在一开始设置的高度是wrap_content,有些图片加载的快,把位置已经占好了,然后随着用户手指的滑动,有些图片还没有加载出来,但是界面已经滑动到更下面了,这些图片没有加载出来,所以导致这样的结果。要解决这样的问题其实也简单,只要在图片加载之前去获取图片的高度,并将ImageView的高度设置好,就能解决这个问题了。
2在adapter中的onBindViewHolder中获取图片的高度,并设置,进行占位代码如下
Glide.with(context)
.load(mDatas.get(position))
.asBitmap()
.placeholder(R.mipmap.ic_launcher)
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
// Do something with bitmap here.
int height = bitmap.getHeight(); //获取bitmap信息,可赋值给外部变量操作,也可在此时行操作。
bitmap.getWidth();
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.iv.getLayoutParams();
layoutParams.height = height;
holder.iv.setLayoutParams(layoutParams);
}
});
这里使用了glide中的SimpleTarget,当资源准备完毕时,可以获取图片的高度,并设置成ImgaeView的高度。但是,如果每次滑动都要去重新获取,这样消耗资源也是很大的。所以在获取的同时,将图片的高度值存储在SpareArray中,这样下次加载时,就可以使用SpareArray中存储的图片的高度值了。所以onBindViewHolder中的代码应该这样写:
if (heightArray.get(position) == null){
Glide.with(context)
.load(mDatas.get(position))
.asBitmap()
.placeholder(R.mipmap.ic_launcher)
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
// Do something with bitmap here.
int height = bitmap.getHeight(); //获取bitmap信息,可赋值给外部变量操作,也可在此时行操作。
bitmap.getWidth();
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.iv.getLayoutParams();
layoutParams.height = height;
holder.iv.setLayoutParams(layoutParams);
heightArray.put(position,height);
}
});
}else {
int height = heightArray.get(position);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.iv.getLayoutParams();
layoutParams.height = height;
holder.iv.setLayoutParams(layoutParams);
}
Glide.with(context)
.load(mDatas.get(position))
.into(holder.iv);
这样就可以解决recyclerview中的图片滑动加载图片错位的问题了。