使用RecyclerView和Glide实现图片瀑布流(防止错位)

来源:互联网 发布:bp算法的基本思想 编辑:程序博客网 时间:2024/06/05 14:32

使用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中的图片滑动加载图片错位的问题了。

0 0