Decorating RecyclerView (with GridLayoutManager) to display divider between items

后端 未结 9 1446
旧时难觅i
旧时难觅i 2020-12-07 09:44

What\'s the best and easiest way to decorate RecyclerView to have such look & feel?

\"enter

9条回答
  •  失恋的感觉
    2020-12-07 10:00

    Here's my version. Based on Nicolay's answer but improved to work with a grid of three or more images & uses dp units for spacing. (His version doesn't give equal sized images/spacing with more than 2 images.)

    NB: the logic to calculate spacing on each image is more complex than just dividing the spacing by two (half for each image) which most answers don't account for..

    /**
     * Class to add INTERNAL SPACING to a grid of items. Only works for a grid with 3 columns or more.
     */
    class PhotoSpaceDecoration extends RecyclerView.ItemDecoration {
        private final int spacingWidthPx;
    
        /**
         * Initialise with the with of the spacer in dp
         *
         * @param spacingWidthDp this will be divided between elements and applied as a space on each side
         *                       NB: for proper alignment this must be divisible by 2 and by the number of columns
         */
        public PhotoSpaceDecoration(Context context, int spacingWidthDp) {
            // Convert DP to pixels
            this.spacingWidthPx = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spacingWidthDp,
                                                                 context.getResources().getDisplayMetrics());
        }
    
        /**
         * @param index           a 0 indexed value of the current item
         * @param numberOfColumns
         * @return a 0 indexed Point with the x & y location of the item in the grid
         */
        private Point getItemXY(int index, int numberOfColumns) {
            int x = index % numberOfColumns;
            int y = index / numberOfColumns; // NB: integer division
            return new Point(x, y);
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            final int position = parent.getChildAdapterPosition(view);
            final int columns = getTotalSpanCount(parent);
            final int rows = (int) Math.ceil(parent.getChildCount() / (double) columns); // NB: NOT integer division
            int spanSize = getItemSpanSize(parent, position);
            if (columns == spanSize) {
                return;
            }
    
            Point point = getItemXY(position, columns);
            int firstMargin = spacingWidthPx * (columns - 1) / columns;
            int secondMargin = spacingWidthPx - firstMargin;
            int middleMargin = spacingWidthPx / 2;
    
            if (point.x == 0) { // first column
                outRect.left = 0;
                outRect.right = firstMargin;
            } else if (point.x == 1) { // second column
                outRect.left = secondMargin;
                outRect.right = rows > 3 ? middleMargin : secondMargin;
            } else if (point.x - columns == -2) { // penultimate column
                outRect.left = rows > 3 ? middleMargin : secondMargin;
                outRect.right = secondMargin;
            } else if (point.x - columns == -1) { // last column
                outRect.left = firstMargin;
                outRect.right = 0;
            } else { // middle columns
                outRect.left = middleMargin;
                outRect.right = middleMargin;
            }
    
            if (point.y == 0) { // first row
                outRect.top = 0;
                outRect.bottom = firstMargin;
            } else if (point.y == 1) { // second row
                outRect.top = secondMargin;
                outRect.bottom = rows > 3 ? middleMargin : secondMargin;
            } else if (point.y - rows == -2) { // penultimate row
                outRect.top = rows > 3 ? middleMargin : secondMargin;
                outRect.bottom = secondMargin;
            } else if (point.y - rows == -1) { // last row
                outRect.top = firstMargin;
                outRect.bottom = 0;
            } else { // middle rows
                outRect.top = middleMargin;
                outRect.bottom = middleMargin;
            }
        }
    
        private int getTotalSpanCount(RecyclerView parent) {
            final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
            return layoutManager instanceof GridLayoutManager ? ((GridLayoutManager) layoutManager).getSpanCount() : 1;
        }
    
        private int getItemSpanSize(RecyclerView parent, int position) {
            final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
            return layoutManager instanceof GridLayoutManager ? ((GridLayoutManager) layoutManager).getSpanSizeLookup()
                                                                                                   .getSpanSize(
                                                                                                           position) : 1;
        }
    }
    

    This is applied to the recycler view from the Activity.onCreate() as below

    photosRecyclerView.addItemDecoration(new PhotoSpaceDecoration(this, 6));
    

    Example:

提交回复
热议问题