RecyclerView使用StaggeredGridLayoutManager实现瀑布流

时间:2021-7-21 作者:qvyue
RecyclerView使用StaggeredGridLayoutManager实现瀑布流
Screenshot_2021-06-17-20-38-52-023_com.ww.myapplication.jpg

header是一个宽度占满全屏的item,下边是一个瀑布流。

要点:
  • 实现瀑布流的要点:设置itemView的高度不一致
  • 防止滑动过程中item错位的要点:来回滑动在复用itemView的时候固定itemView的高度,策略是在给itemView设置高度的Model数据中固定高度数据。
  • 更新数据要点:瀑布流添加数据更新的时候,需要使用notifyItemInserted(data.size()),data.size()是添加数据后集合的大小

下边展示代码:
MainActivity的布局文件:activity_main.xml



    

普通itemView的布局文件:item_normal.xml

Header的布局文件:item_header.xml

给Adapter的数据,封装成了一个Model,每个itemView的高度来源于这个Model

package com.ww.myapplication.model;

public class ImageModel {
    private int imageRes;
    private String desc;
    // 图片的高度
    private double imageHeight;

    public ImageModel(int imageRes, String desc, double imageHeight) {
        this.imageRes = imageRes;
        this.desc = desc;
        this.imageHeight = imageHeight;
    }

    public int getImageRes() {
        return imageRes;
    }

    public void setImageRes(int imageRes) {
        this.imageRes = imageRes;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public double getImageHeight() {
        return imageHeight;
    }

    public void setImageHeight(double imageHeight) {
        this.imageHeight = imageHeight;
    }
}

MainActivity中调用的代码:

package com.ww.myapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.ww.myapplication.adapter.MyAdapter;
import com.ww.myapplication.adapter.SpaceItemDecoration;
import com.ww.myapplication.databinding.ActivityMainBinding;
import com.ww.myapplication.model.ImageModel;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 练习constraintLayout
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static String TAG = "== MainActivity ==>";
    private ActivityMainBinding binding;

    private List imageModels = new ArrayList();
    private int[] imgRes = {
            R.drawable.img1,
            R.drawable.img2,
            R.drawable.img3,
            R.drawable.cat,
            R.drawable.cat2,
            R.drawable.lion2,
            R.drawable.lion1
    };
    private String[] descNames = {
            "春风又绿江南岸",
            "十步杀一人,千里不留行",
            "明月何时照我还",
            "君不见,黄河之水天上来",
            "蜀道难,难于上青天",
            "落霞与孤鹜齐飞",
            "关山难越,谁悲失路之人",
            "两岸猿声啼不住",
            "海上生明月,天涯共此时",
            "乘舟侧畔千帆过",
            "青青子衿,依依我心"
    };
    private MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(LayoutInflater.from(this));
        setContentView(binding.getRoot());

        binding.btn.setOnClickListener(this);

        increaseData();

        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
        binding.rv.setLayoutManager(staggeredGridLayoutManager);

       // 设置网格布局
       //  GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
       //   binding.rv.setLayoutManager(gridLayoutManager);

        SpaceItemDecoration dividerItemDecoration = new SpaceItemDecoration(16);
        binding.rv.addItemDecoration(dividerItemDecoration);

        myAdapter = new MyAdapter();

        TextView textView = new TextView(this);
        LinearLayout.LayoutParams textViewLp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 50);
        textViewLp.gravity = Gravity.CENTER;
        textView.setText("这是Header Item");
        textView.setTextColor(Color.parseColor("#000000"));
        textView.setGravity(Gravity.CENTER);
        textView.setLayoutParams(textViewLp);
        myAdapter.addHeader(textView);

        binding.rv.setAdapter(myAdapter);

        myAdapter.addData(imageModels);


    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn) {

            myAdapter.addData(increaseData());


        }
    }

    private List increaseData() {
        imageModels.clear();

        Random random = new Random();
        // 初始数据
        for (int i = 0; i 

MyAdapter的代码:

package com.ww.myapplication.adapter;

import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.ww.myapplication.R;
import com.ww.myapplication.model.ImageModel;

import java.util.ArrayList;
import java.util.List;

public class MyAdapter extends RecyclerView.Adapter {

    public static int ITEM_HEADER = 0x012;
    public static int ITEM_NORMAL = 0x013;
    public static int ITEM_FOOTER = 0x014;

    private List headerList = new ArrayList();
    private List footerList = new ArrayList();
    private List data;

    public MyAdapter() {
        data = new ArrayList();
    }

    public void addData(List newData) {
        if (newData != null && newData.size() > 0) {
            data.addAll(newData);
            notifyItemInserted(data.size());
        }
    }

    public void addFooter(View view) {
        if (view != null) {
            footerList.add(view);
        }
    }

    public void addHeader(View view) {
        if (view != null) {
            headerList.add(view);
        }
    }

    @Override
    public int getItemViewType(int position) {

        if (position = (headerList.size() + data.size())) {
            // footer item
            return ITEM_FOOTER;
        } else {
            // 正常的Item
            return ITEM_NORMAL;
        }
    }

    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = null;
        if (viewType == ITEM_HEADER || viewType == ITEM_FOOTER) {
            // header item
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_header, parent, false);
        } else {
            // 正常普通的item
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_normal, parent, false);
        }
        return new MyHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        if (holder.getItemViewType() == ITEM_HEADER) {
            LinearLayout headerViewParent = (LinearLayout) holder.itemView;
            if (headerViewParent.getChildCount() == 0) {
                Log.d("==TAG==>", "添加 header 子View");
                for (View view : headerList) {
                    // 将header view添加到itemView中
                    headerViewParent.addView(view);
                }
            }
        } else if (holder.getItemViewType() == ITEM_FOOTER) {
            LinearLayout footerViewParent = (LinearLayout) holder.itemView;
            if (footerViewParent.getChildCount() == 0) {
                Log.d("==TAG==>", "添加 footer 子View");
                for (View view : footerList) {
                    // 将footer view添加到itemView中
                    footerViewParent.addView(view);
                }
            }
        } else {
            ImageModel imageModel = data.get(position - headerList.size());

            RecyclerView.LayoutManager manager = mRecyclerView.getLayoutManager();
            if (manager instanceof StaggeredGridLayoutManager) {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth * imageModel.getImageHeight());
                holder.showIv.setLayoutParams(lp);
            } else if (manager instanceof GridLayoutManager) {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth * 2 / 3);
                holder.showIv.setLayoutParams(lp);
            } else {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth / 3);
                holder.showIv.setLayoutParams(lp);
            }
            holder.descTv.setText(imageModel.getDesc());
            holder.showIv.setImageResource(imageModel.getImageRes());
        }


    }

    private RecyclerView mRecyclerView;

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.mRecyclerView = recyclerView;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 指定每个item占用几个网格坑位
                    if (position = (headerList.size()) + data.size()) {
                        // header 或者 footer
                        return gridLayoutManager.getSpanCount();
                    }
                    return 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(@NonNull MyHolder holder) {
        super.onViewAttachedToWindow(holder);
        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
            // 瀑布流的布局参数
            StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) lp;
            if (holder.getItemViewType() == ITEM_HEADER || holder.getItemViewType() == ITEM_FOOTER) {
                layoutParams.setFullSpan(true);
                holder.itemView.setLayoutParams(layoutParams);
            } else {
                layoutParams.setFullSpan(false);
                holder.itemView.setLayoutParams(layoutParams);
            }
        }
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
    }

    @Override
    public void onViewDetachedFromWindow(@NonNull MyHolder holder) {
        super.onViewDetachedFromWindow(holder);
    }

    @Override
    public int getItemCount() {
        return data.size() + headerList.size() + footerList.size();
    }

    static class MyHolder extends RecyclerView.ViewHolder {

        private final ImageView showIv;
        private final TextView descTv;

        public MyHolder(@NonNull View itemView) {
            super(itemView);
            showIv = itemView.findViewById(R.id.show_iv);
            descTv = itemView.findViewById(R.id.desc_tv);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(itemView.getContext(), "position:" + getLayoutPosition(), Toast.LENGTH_SHORT).show();
                }
            });

        }
    }

    public int getScreenWidth(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    public int getScreenHeight(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }


}

每个itemView的分割线:

package com.ww.myapplication.adapter;

import android.graphics.Rect;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpaceItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.left = space;
        outRect.top = space;
        outRect.right = space;
        outRect.bottom = space;
    }
}

recyclerView

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。