Android RecyclerView总结

RecyclerView总结

概述

RecyclerView是谷歌官方推出的一个用于大量数据展示的新空间,可以说是一个增强的ListView,优化了ListView的不足之处,更加强大和灵活。

基本实现

列表布局

线性布局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new FruitAdapter(this, mDatas);
recyclerView.setAdapter(mAdapter);
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    
    
    private final Context mContext;
    private final ArrayList<Fruit> mDatas;
    private final LayoutInflater layoutInflater;

    public FruitAdapter(Context context, ArrayList<Fruit> datas) {
    
    
        mContext = context;
        mDatas = datas;
        layoutInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        View itemView = layoutInflater.inflate(R.layout.item_linear_fruit, parent, false);
        ViewHolder viewHolder = new ViewHolder(itemView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
        Fruit fruit = mDatas.get(position);
        holder.name.setText(fruit.getName());
        holder.img.setImageResource(fruit.getImg());
    }

    @Override
    public int getItemCount() {
    
    
        return mDatas.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
    
    
        TextView name;
        ImageView img;

        public ViewHolder(@NonNull View itemView) {
    
    
            super(itemView);
            name = itemView.findViewById(R.id.name);
            img = itemView.findViewById(R.id.img);
        }
    }
}

网格布局

网格布局
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);
recyclerView.setLayoutManager(gridLayoutManager);
FruitAdapter mAdapter = new FruitAdapter(this, mDatas);
recyclerView.setAdapter(mAdapter);
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    
    

    private final Context mContext;
    private final ArrayList<Fruit> mDatas;
    private final LayoutInflater layoutInflater;

    public FruitAdapter(Context context, ArrayList<Fruit> datas) {
    
    
        mContext = context;
        mDatas = datas;
        layoutInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        View itemView = layoutInflater.inflate(R.layout.item_grid_fruit, parent, false);
        ViewHolder viewHolder = new ViewHolder(itemView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
        Fruit fruit = mDatas.get(position);
        holder.name.setText(fruit.getName());
        holder.img.setImageResource(fruit.getImg());
    }

    @Override
    public int getItemCount() {
    
    
        return mDatas.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
    
    
        TextView name;
        ImageView img;

        public ViewHolder(@NonNull View itemView) {
    
    
            super(itemView);
            name = itemView.findViewById(R.id.name);
            img = itemView.findViewById(R.id.img);
        }
    }
}

瀑布流布局

瀑布流布局
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
FruitAdapter mAdapter = new FruitAdapter(this, mDatas);
recyclerView.setAdapter(mAdapter);
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    
    

    private final Context mContext;
    private final ArrayList<Fruit> mDatas;
    private final LayoutInflater layoutInflater;

    public FruitAdapter(Context context, ArrayList<Fruit> datas) {
    
    
        mContext = context;
        mDatas = datas;
        layoutInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        View itemView = layoutInflater.inflate(R.layout.item_fruit_desc, parent, false);
        ViewHolder viewHolder = new ViewHolder(itemView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
        Fruit fruit = mDatas.get(position);
        holder.name.setText(fruit.getName());
        holder.img.setImageResource(fruit.getImg());
        holder.desc.setText(fruit.getDesc());
    }

    @Override
    public int getItemCount() {
    
    
        return mDatas.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
    
    
        TextView name;
        ImageView img;
        TextView desc;

        public ViewHolder(@NonNull View itemView) {
    
    
            super(itemView);
            name = itemView.findViewById(R.id.name);
            img = itemView.findViewById(R.id.img);
            desc = itemView.findViewById(R.id.desc);
        }
    }
}

设置分割线

ItemDecoration类介绍

RecyclerView中的分割线通继承RecyclerView.ItemDecoration类实现,ItemDecoration中有3个方法:

  • getItemOffsets(): 设置itemView的偏移量。
  • onDraw(): 通过Canvas绘制分割线内容,ItemDecoration的onDraw()早于itemView的onDraw()执行。
  • onDrawOver(): 与onDraw()类似,在itemView的onDraw()之后执行。

基本实现

列表布局中的分割线

public class LinearItemDecoration extends RecyclerView.ItemDecoration {
    
    
    //RecyclerView布局方向
    private int mOrientation = LinearLayoutManager.VERTICAL;
    //分割线大小
    private int mDividerSize = 1;
    //分割线颜色
    private int mColor = Color.RED;
    //Drawable分割线
    private Drawable mDividerDrawable;

    private Paint mPaint;
    private final Context mContext;

    /**
     * @param context
     * @param orientation 列表方向
     * @param color       颜色
     * @param dividerSize 分割线大小
     */
    public LinearItemDecoration(Context context, int orientation, int color, int dividerSize) {
    
    
        mContext = context;
        mOrientation = orientation;
        mColor = color;
        mDividerSize = dividerSize;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(mColor);
        mPaint.setStyle(Paint.Style.FILL);
    }

    public LinearItemDecoration(Context context, int orientation, int drawableId) {
    
    
        mContext = context;
        mOrientation = orientation;
        mDividerDrawable = ContextCompat.getDrawable(context, drawableId);
        mDividerSize = mDividerDrawable.getIntrinsicHeight();
    }

    //设置分割线颜色
    public void setColor(int color) {
    
    
        mPaint.setColor(color);
    }

    //设置分割线大小
    public void setDividerSize(int size) {
    
    
        mDividerSize = size;
    }

    /**
     * 设置分割线大小
     */
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
    
    
        if (mOrientation == LinearLayout.VERTICAL) {
    
    
            outRect.set(0, 0, 0, mDividerSize);
        } else {
    
    
            outRect.set(0, 0, mDividerSize, 0);
        }
    }

    /**
     * 绘制分割线
     */
    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
    
    
        if (mOrientation == LinearLayout.VERTICAL) {
    
    
            drawVertical(c, parent);
        } else {
    
    
            drawHorizontal(c, parent);
        }
    }

    /**
     * 垂直方向分割线绘制
     */
    private void drawVertical(@NonNull Canvas c, @NonNull RecyclerView parent) {
    
    
        final int left = parent.getPaddingLeft();
        final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
        final int childSize = parent.getChildCount();
        for (int i = 0; i < childSize; i++) {
    
    
            final View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
            final int top = childView.getBottom() + layoutParams.bottomMargin;
            final int bottom = top + mDividerSize;
            if (mDividerDrawable == null) {
    
    
                c.drawRect(left, top, right, bottom, mPaint);
            } else {
    
    
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    }

    /**
     * 水平方向分割线绘制
     */
    private void drawHorizontal(@NonNull Canvas c, @NonNull RecyclerView parent) {
    
    
        final int top = parent.getPaddingTop();
        final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
        final int childSize = parent.getChildCount();
        for (int i = 0; i < childSize; i++) {
    
    
            final View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
            final int left = childView.getRight() + layoutParams.rightMargin;
            final int right = left + mDividerSize;
            if (mDividerDrawable == null) {
    
    
                c.drawRect(left, top, right, bottom, mPaint);
            } else {
    
    
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    }
}
//LinearItemDecoration linearItemDecoration = new LinearItemDecoration(this, LinearLayoutManager.VERTICAL, Color.BLACK, 1);
//或
LinearItemDecoration linearItemDecoration = new LinearItemDecoration(this, LinearLayoutManager.VERTICAL, R.drawable.shap_divider);
recyclerView.addItemDecoration(linearItemDecoration);

网格布局中的分割线

与列表布局中的分割线基本类似

public class GridItemDecoration extends RecyclerView.ItemDecoration {
    
    
    private int mDividerSize = 10;
    private Paint mPaint;
    private final Context mContext;

    public GridItemDecoration(Context context) {
    
    
        mContext = context;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
    }

    public void setColor(int color) {
    
    
        mPaint.setColor(color);
    }

    /**
     * 获取RecyclerView列数
     */
    private int getSpanCount(RecyclerView parent) {
    
    
        int spanCount = -1;
        GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
        spanCount = layoutManager.getSpanCount();
        return spanCount;
    }

    /**
     * 是否最后一列
     */
    private boolean isLastColumn(RecyclerView parent, int position, int spanCount, int childCount) {
    
    
        if ((position + 1) % spanCount == 0) {
    
    
            return true;
        } else {
    
    
            return false;
        }
    }

    /**
     * 是否最后一行
     */
    private boolean isLastRow(RecyclerView parent, int position, int spanCount, int childCount) {
    
    
        childCount = childCount - childCount % spanCount;
        if (position >= childCount) {
    
    
            return true;
        } else {
    
    
            return false;
        }
    }

    /**
     * 设置分割线大小
     */
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
    
    
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        int position = parent.getChildAdapterPosition(view);
        if (isLastRow(parent, position, spanCount, childCount)) {
    
    
            //最后一行不绘制底部
            outRect.set(0, 0, mDividerSize, 0);
        } else if (isLastColumn(parent, position, spanCount, childCount)) {
    
    
            //最后一列不绘制右边
            outRect.set(0, 0, 0, mDividerSize);
        } else {
    
    
            outRect.set(0, 0, mDividerSize, mDividerSize);
        }
    }

    /**
     * 绘制分割线
     */
    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
    
    
        drawVertical(c, parent);
        drawHorizontal(c, parent);
    }

    /**
     * 绘制垂直分割线
     */
    private void drawVertical(@NonNull Canvas c, @NonNull RecyclerView parent) {
    
    
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
    
    
            final View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
            final int left = childView.getRight() + layoutParams.rightMargin;
            final int top = childView.getTop() - layoutParams.topMargin;
            final int right = left + mDividerSize;
            final int bottom = childView.getBottom() + layoutParams.bottomMargin;
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }

    /**
     * 绘制水平分割线
     */
    private void drawHorizontal(@NonNull Canvas c, @NonNull RecyclerView parent) {
    
    
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
    
    
            final View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
            fnal int left = childView.getLeft() - layoutParams.leftMargin;
            final int top = childView.getBottom() + layoutParams.bottomMargin;
            final int right = childView.getRight() + layoutParams.rightMargin + mDividerSize;
            final int bottom = top + mDividerSize;
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }
}
recyclerView.addItemDecoration(new GridItemDecoration(this));

数据增删改操作

//增加数据
//指定位置添加一个数据
void notifyItemInserted(int position)
//指定位置添加多个数据
void notifyItemRangeInserted(int positionStart, int itemCount)

//删除数据
//删除指定位置的一个数据
void notifyItemRemoved(int position)
//删除指定位置的多个数据
void notifyItemRangeRemoved(int positionStart, int itemCount) 

//修改数据
//修改指定位置的数据
void notifyItemChanged(int position) 
//修改指定位置的多个数据
void notifyItemRangeChanged(int positionStart, int itemCount)

//刷新列表
void void notifyDataSetChanged()

DiffUtil的使用

在实际开发中,可能需要修改多个数据源,这是需要直接调用notifyDataSetChanged()更新列表,但使用notifyDataSetChanged()存在一些缺点,如:不会触发动画、性能偏低,这时可以借助DiffUtil。

DiffUtil适用于比较两个数据源,计算它们之间的差值,然后进行定制操作。

基本实现

public class AdapterDiffCallback extends DiffUtil.Callback {
    
    
    private ArrayList<User> mOldList;
    private ArrayList<User> mNewList;

    public AdapterDiffCallback(ArrayList<User> oldList, ArrayList<User> newList) {
    
    
        mOldList = oldList;
        mNewList = newList;
    }

    @Override
    public int getOldListSize() {
    
    
        return mOldList.size();
    }

    @Override
    public int getNewListSize() {
    
    
        return mNewList.size();
    }

    /**
     * 判断是否同一个item
     */
    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    
    
        return mOldList.get(oldItemPosition).getId() == mNewList.get(newItemPosition).getId();
    }

    /**
     * 比较两个item的内容是否相同
     */
    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
    
    
        String oldName = mOldList.get(oldItemPosition).getName();
        String oldAddress = mOldList.get(oldItemPosition).getAddress();
        int oldAge = mOldList.get(oldItemPosition).getAge();

        String newName = mNewList.get(newItemPosition).getName();
        String newAddress = mNewList.get(newItemPosition).getAddress();
        int newAge = mNewList.get(newItemPosition).getAge();

        return oldAddress.equals(newAddress) && oldName.equals(newName) && oldAge == newAge;
    }
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    
    
    public void setDatas(ArrayList<User> datas) {
    
    
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new AdapterDiffCallback(mDatas, datas), true);
        diffResult.dispatchUpdatesTo(this);
        //更新数据源,必须放在dispatchUpdatesTo之后
        mDatas = datas;
    }
}

使用

ArrayList<User> newDatas = new ArrayList<>();
for (User user : mDatas) {
    
    
    newDatas.add(user.clone());
}
newDatas.get(3).setAge(333333);
newDatas.get(3).setAddress("6666666");
newDatas.remove(0);
newDatas.add(new User(18, "新姓名18", 18, "新地址18"));
mAdapter.setDatas(newDatas);

代码下载

https://github.com/xiangxiongfly/RecyclerViewDemo

猜你喜欢

转载自blog.csdn.net/qq_14876133/article/details/112094700
今日推荐