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

https://blog.csdn.net/qq_20949825/article/details/52103395

https://blog.csdn.net/life90/article/details/78884618?utm_medium=distribute.pc_relevant_t0.none-task-blog-OPENSEARCH-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-OPENSEARCH-1.control

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

猜你喜欢

转载自blog.csdn.net/az44yao/article/details/113112903
今日推荐