美文网首页Android开发知识小集
RecyclerView 在项目中使用的常见问题

RecyclerView 在项目中使用的常见问题

作者: d74f37143a31 | 来源:发表于2018-11-21 00:01 被阅读128次

    ItemDecoration

    常见的作用有:分割线、吸顶效果、时光轴等 推荐阅读 https://blog.csdn.net/briblue/article/details/70161917

    线性分割线:

    以下代码来源于网络,在项目中测试可以通过。

    public class RecycleViewDivider extends RecyclerView.ItemDecoration {
        private Paint mPaint;
        private Drawable mDivider;
        private int mDividerHeight = 2;//分割线高度,默认为1px
        private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
        private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    
        /**
         * 默认分割线:高度为2px,颜色为灰色
         *
         * @param context
         * @param orientation 列表方向
         */
        public RecycleViewDivider(Context context, int orientation) {
            if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
                throw new IllegalArgumentException("请输入正确的参数!");
            }
            mOrientation = orientation;
    
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            mDivider = a.getDrawable(0);
            a.recycle();
        }
    
        /**
         * 自定义分割线
         *
         * @param context
         * @param orientation 列表方向
         * @param drawableId  分割线图片
         */
        public RecycleViewDivider(Context context, int orientation, int drawableId) {
            this(context, orientation);
            mDivider = ContextCompat.getDrawable(context, drawableId);
            mDividerHeight = mDivider.getIntrinsicHeight();
        }
    
        /**
         * 自定义分割线
         *
         * @param context
         * @param orientation   列表方向
         * @param dividerHeight 分割线高度
         * @param dividerColor  分割线颜色
         */
        public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
            this(context, orientation);
            mDividerHeight = dividerHeight;
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(dividerColor);
            mPaint.setStyle(Paint.Style.FILL);
        }
    
    
        //获取分割线尺寸
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            outRect.set(0, 0, 0, mDividerHeight);
        }
    
        //绘制分割线
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            if (mOrientation == LinearLayoutManager.VERTICAL) {
                drawVertical(c, parent);
            } else {
                drawHorizontal(c, parent);
            }
        }
    
        //绘制横向 item 分割线
        private void drawHorizontal(Canvas canvas, 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 child = parent.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int top = child.getBottom() + layoutParams.bottomMargin;
                final int bottom = top + mDividerHeight;
                if (mDivider != null) {
                    mDivider.setBounds(left, top, right, bottom);
                    mDivider.draw(canvas);
                }
                if (mPaint != null) {
                    canvas.drawRect(left, top, right, bottom, mPaint);
                }
            }
        }
    
        //绘制纵向 item 分割线
        private void drawVertical(Canvas canvas, 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 child = parent.getChildAt(i);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int left = child.getRight() + layoutParams.rightMargin;
                final int right = left + mDividerHeight;
                if (mDivider != null) {
                    mDivider.setBounds(left, top, right, bottom);
                    mDivider.draw(canvas);
                }
                if (mPaint != null) {
                    canvas.drawRect(left, top, right, bottom, mPaint);
                }
            }
        }
    }
    

    网格分割线:

    以下代码来源于网络,在项目中测试可以通过。

    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
        private int spanCount;
        private int spacing;
        private boolean includeEdge;
    
        public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacing = spacing;
            this.includeEdge = includeEdge;
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column
    
            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
    
                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        }
    

    侧拉菜单

    实现原理暂时还没去阅读源码,实现的功能就是在 RecyclerView的每个Item添加上侧拉出来的布局,通过侧拉出来的布局实现一些功能。具体可到 Github 搜索 这个库PinnedSectionItemDecoration,上面有实现的效果。

    compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
    compile 'com.oushangfeng:PinnedSectionItemDecoration:1.2.7'
    compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-5'
    
    

    SnapHelper

    参考:让你明明白白的使用RecyclerView——SnapHelper详解
    SnapHelper是一个抽象类,官方提供了一个LinearSnapHelper的子类,可以让RecyclerView滚动停止时相应的Item停留中间位置。25.1.0版本中官方又提供了一个PagerSnapHelper的子类,可以使RecyclerView像ViewPager一样的效果,一次只能滑一页,而且居中显示。

    这两个子类使用方式也很简单,只需要创建对象之后调用attachToRecyclerView()附着到对应的RecyclerView对象上就可以了

    new LinearSnapHelper().attachToRecyclerView(mRecyclerView);
    //或者
    new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
    

    局部刷新

    例如点击item中的某个控件,刷新该控件对应的点击数。

        // 定义的刷新函数
        adapter.refreshPositionItem(view,count,position);
        adapter.notifyItemChanged(position,0);
    

    在 adapter 中添加一个方法

    public void refreshPositionItem(View view, int count, int position) {
        TextView tvCount = view.findViewById(R.id.tv_count);
        tvCount.setText(count+"");
    }
    

    由于复用导致数据的错乱问题

    一定要修改源数据源后再刷新 adapter ,这就不会错乱了

    参考
    Android RecyclerView详解

    相关文章

      网友评论

        本文标题:RecyclerView 在项目中使用的常见问题

        本文链接:https://www.haomeiwen.com/subject/nbnfqqtx.html