Use RecyclerView and Glide to achieve picture waterfall flow (to prevent dislocation)

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

Use RecyclerView and Glide to achieve picture waterfall flow (to prevent dislocation)

Recently I am learning Android's new control RecyclerView. I feel that this is a control with a high degree of freedom. In addition to the most basic ListView and GridView functions, it can also achieve the effect of waterfall flow. Android RecyclerView uses a fully analytical and artistic control , which explains in detail how to use and customize RecyclerView. This blog is about the pits I encountered when using RecyclerView and Glide to implement the waterfall function.

First post the activity, layout code

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>

The layout of activity is very simple, there is only one recyclerview, the code in activiy is also the most basic code to load the recyclerview.
Then the adapter code

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);
        }
    }

}

Glide picture frame is used in the onBindViewHolder in the adapter to load pictures. In this way, a basic waterfall flow loading image is realized. But the waterfall stream loaded in this way will have the picture dislocation when sliding. In order to solve this problem, the following steps are required:

1. Add manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE) in the activity; this code can prevent the recyclerview item from being misplaced during the loading process. However, after adding this code, the image loading problem of the recyclerview is even greater, sometimes even large blanks appear, as shown in the following figure:
Write picture description here

Damn it, why don't you add this code? Don't worry, this code is to prevent item misalignment and position changes, but the height of the picture is set at the beginning of wrap_content, some pictures load fast, the position is already occupied, and then as the user's finger slides, some pictures It has not been loaded yet, but the interface has been slid to the bottom. These pictures have not been loaded, which leads to this result. To solve this problem is actually simple, as long as the height of the image is obtained before the image is loaded, and the height of the ImageView is set, this problem can be solved.

2 Get the height of the picture in the onBindViewHolder in the adapter, and set it, and the placeholder code is as follows

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);

                        }

                    });

Here, the SimpleTarget in glide is used. When the resource is ready, the height of the picture can be obtained and set to the height of ImgaeView. However, if you have to reacquire each time you swipe, this consumes a lot of resources. Therefore, while obtaining, store the height value of the picture in SpareArray, so that the height value of the picture stored in SpareArray can be used when it is loaded next time. So the code in onBindViewHolder should be written like this:

 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);

This can solve the problem of dislocation of pictures in the recyclerview sliding loading pictures.

Guess you like

Origin blog.csdn.net/az44yao/article/details/113112903