RecyclerView使用方法(一)

RecyclerView可以替换ListView,GridView完成线性、网格、瀑布的显示,我们只需要根据需求设置对应的LayoutManager就可以了。
LinearLayoutManager
GridLayoutManager
StaggeredGridLayoutManager

RecyclerView基本方法使用步骤:
1、在布局中增加RecyclerView控件
mRecyclerView = findViewById(R.id.recyclerview);
2、设置适配器
MyRecyclerAdapter adapter = new MyRecyclerAdapter(getIntList(), width);
mRecyclerView.setAdapter(adapter);
3、设置动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
4、设置布局
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
5、设置分割线
mRecyclerView.addItemDecoration(new LinearItemDecoration(this, LinearLayoutManager.VERTICAL, false));


1、线程RecyclerView
先来看下采用LinearLayoutManager的代码
其中adapter、LinearItemDecoration均需要自定义,如下是这两个类的关键方法
MyRecyclerAdapter继承于RecyclerView.Adapter

public MyRecyclerAdapter(List<String> list, int screenWidth) {
    super();
    mList = list;
    mScreenWidth = screenWidth;
}

@NonNull
@Override
public MyRecyclerAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);
    return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    holder.textView.setText((String)mList.get(position));
}

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

在MyRecyclerAdapter中定义了内部类

class MyViewHolder extends RecyclerView.ViewHolder {
    TextView textView;

    public MyViewHolder(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.textview);
        textView.setOnClickListener(mViewOnClickListener);
    }
}

该写法跟ListView很类似,只是要注意onCreateViewHolder用来创建ViewHolder,而onBindViewHolder用来完成数据绑定。
接下来完成分割线的绘制,我们只需要继承RecyclerView.ItemDecoration
后在指定的方法中绘制分割线就可以了,一般在onDraw方法中完成,而onDrawOver是在RecyclerView绘制完后会被调用,可以用来绘制悬浮标题。getItemOffsets方法的作用是获取子View偏移值,类似于padding值,在这里重写的目的是偏移一定的空间用来绘制分割线。具体实现如下:

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    if (mOrientation == LinearLayoutManager.VERTICAL) {
        drawVertical(c, parent);
    } else if (mOrientation == LinearLayoutManager.HORIZONTAL) {
        drawHorizontal(c, parent);
    }
}

private void drawVertical(Canvas c, RecyclerView parent) {
    int left, right, top, buttom;
    int childCount = parent.getChildCount();
    left = parent.getPaddingLeft();
    right = parent.getWidth() - left - parent.getPaddingRight();
    for (int i = 0; i < childCount; i++) {
        View child = parent.getChildAt(i);
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
        top = child.getBottom() + layoutParams.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
        buttom = top + mDrawable.getIntrinsicHeight();
        mDrawable.setBounds(left, top, right, buttom);
        mDrawable.draw(c);
    }
}

private void drawHorizontal(Canvas c, RecyclerView parent) {
    int left, right, top, buttom;
    int childCount = parent.getChildCount();
    top = parent.getPaddingTop();
    buttom = parent.getHeight() - top - parent.getPaddingBottom();
    for (int i = 0; i < childCount; i++) {
        View child = parent.getChildAt(i);
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
        left = child.getRight() + layoutParams.rightMargin + Math.round(ViewCompat.getTranslationX(child));
        right = left + mDrawable.getIntrinsicWidth();
        mDrawable.setBounds(left, top, right, buttom);
        mDrawable.draw(c);
    }
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    if (mOrientation == LinearLayoutManager.VERTICAL) {
    outRect.set(0, 0, 0, mDrawable.getIntrinsicHeight());
    } else if (mOrientation == LinearLayoutManager.HORIZONTAL) {
        outRect.set(0, 0, mDrawable.getIntrinsicWidth(), 0);
    }
}

这样,基本的线性RecyclerView就完成了,效果图如下:

这里写图片描述

2、网格RecyclerView
接下来是网格列表,需要设置LayoutManager和ItemDecoration
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5));
mRecyclerView.addItemDecoration(new GridItemDecoration(this, 5));
这里的数字5代表的是一行有5个子View
来看下GridItemDecoration的实现,这里需要注意的是要画垂直和水平的分割线,思路是针对垂直线,只需要画子View右边的分割线,最右边的子View则不需要画分割线;针对水平线,只需要画子View下面的分割线。而getItemOffsets同样也是要考虑最右边和最底层时,不要进行偏移的。

public class GridItemDecoration extends RecyclerView.ItemDecoration {
    private int attrs[] = new int[] {android.R.attr.listDivider};
    private Context mContext;
    private Drawable mDrawable;
    private int mSpanCount;
    public GridItemDecoration(Context context, int spanCount) {
        mContext = context;
        mSpanCount = spanCount;
        TypedArray typedArray = context.obtainStyledAttributes(attrs);
        mDrawable = typedArray.getDrawable(0);
        typedArray.recycle();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent) {
        drawVertical(c,parent);
        drawHorizontal(c, parent);
    }

    private void drawVertical(Canvas c, RecyclerView parent) {// 竖线
        int count = parent.getChildCount();
        int left, top, right, buttom;
        for (int i = 0; i < count; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
            left = child.getRight() + params.rightMargin;
            right = left + mDrawable.getIntrinsicWidth();
            top = child.getTop() - params.topMargin;
            buttom = child.getBottom() + params.bottomMargin;
            mDrawable.setBounds(left, top, right, buttom);
            mDrawable.draw(c);
        }
    }

    private void drawHorizontal(Canvas c, RecyclerView parent) {// 横线
        int count = parent.getChildCount();
        int left, top, right, buttom;
        for (int i = 0; i < count; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
            left = child.getLeft() - params.leftMargin;
            right = child.getRight() + params.rightMargin;
            top = child.getBottom() + params.bottomMargin;
            buttom = top + mDrawable.getIntrinsicHeight();
            mDrawable.setBounds(left, top, right, buttom);
            mDrawable.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int right = mDrawable.getIntrinsicWidth();
        int buttom = mDrawable.getIntrinsicHeight();
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
        int position = params.getViewAdapterPosition() + 1;
        if (isLastColum(position, parent)) {
            right = 0;
        }
        if (isLastRow(position, parent)) {
            buttom = 0;
        }
        outRect.set(0, 0, right, buttom);
    }

    private boolean isLastRow(int position, RecyclerView parent) {
        int count = parent.getAdapter().getItemCount();
        int lastRowCount = count % mSpanCount;
        int rowCount = lastRowCount == 0 ? count / mSpanCount : count / mSpanCount + 1;
        if (position / mSpanCount == rowCount || (position % mSpanCount != 0
                    && position / mSpanCount == rowCount -1)) {
            return true;
        }
        return false;
    }

    private boolean isLastColum(int position, RecyclerView parent) {
        return position % mSpanCount == 0;
    }
}

效果图如下:

这里写图片描述

3、瀑布RecyclerView
最后是瀑布网格列表,同样需要设置需要设置LayoutManager和ItemDecoration
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.VERTICAL));
mRecyclerView.addItemDecoration(new StaggeredItemDecoration(this, 5));
这里为了体现瀑布流中各单元大小不一致,在MyRecyclerAdapter修改了子View高度:

@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    holder.textView.setText((String)mList.get(position));
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mScreenWidth / 5, 150);
    if (position % 2 != 0) {
        params.height = 200;
        holder.textView.setBackgroundColor(Color.GREEN);
    } else {
        holder.textView.setBackgroundColor(Color.YELLOW);
    }

    holder.textView.setLayoutParams(params);

}

然后到了画分割线的时候了,这里要注意的一点是,由于高度不一致,子View的布局并不会按照从上往下,从左往右的顺序排列,当上一行排列完成后,下以后的第一个View会优先选择从左往右的第一个高度较小的。换一句话说,之前的线性和网格布局使用的position,在这里无法继续使用了。不过思路还是一样的,先考虑偏移量,偏移量出来了,我们就用分割线去填充。设置一个space,子View左右两边偏移space,第二行开始,子View上面偏移2 * space,这里2倍的意思是两个View的中间距离实际是一个View的右偏移量加上第二个View的左偏移量。然后画垂直的分割线,这里要注意的是宽度是一定的即2 * space,高度则是子View 的top到buttom的距离,而水平分割线为了把对角的子View间的空间填充,必须将左右距离设置为从子View的left到right + 2 * space。代码如下:

public class StaggeredItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDrawable;
    private Context mContext;
    private static final int SPACE = 5;
    private int mSpanCount;
    private int attrs[] = new int[]{android.R.attr.listDivider};

    public StaggeredItemDecoration(Context context, int spanCount) {
        mContext = context;
        mSpanCount = spanCount;
        TypedArray typedArray = context.obtainStyledAttributes(attrs);
        mDrawable = typedArray.getDrawable(0);
        typedArray.recycle();
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildLayoutPosition(view);
        int top = 0;
        int left = SPACE;
        int right = SPACE;
        if (position >= mSpanCount) {
            top = SPACE * 2;
        }
        outRect.set(left, top, right, 0);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        drawHorizontal(c, parent);
        drawVertical(c, parent);
    }

    private void drawVertical(Canvas c, RecyclerView parent) {
        int count = parent.getChildCount();
        int left = 0, top = 0, right = 0, buttom = 0;
        for (int i = 0; i < count; i++) {
            View view = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
            left = view.getRight();
            right = left + SPACE * 2;
            top = view.getTop();
            buttom = view.getBottom();
            mDrawable.setBounds(left, top, right, buttom);
            mDrawable.draw(c);
        }
    }

    private void drawHorizontal(Canvas c, RecyclerView parent) {
        int count = parent.getChildCount();
        int left = 0, top = 0, right = 0, buttom = 0;
        for (int i = 0; i < count; i++) {
            View view = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
            top = view.getBottom();
            buttom = top + SPACE * 2;
            left = view.getLeft();
            right = view.getRight() + SPACE * 2;
            mDrawable.setBounds(left, top, right, buttom);
            mDrawable.draw(c);
        }
    }
}

效果图如下:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/rhythmjay/article/details/80864319