GridLayoutManager - how to auto fit columns?

后端 未结 8 1973
野性不改
野性不改 2020-11-30 18:30

I have a RecyclerView with a GridLayoutManager that displays Card Views. I want the cards to rearrange according to the screen size (the Google Play app does this kind of th

相关标签:
8条回答
  • 2020-11-30 19:09

    The GridLayoutManager's constructor has an argument spanCount that is

    The number of columns in the grid

    You can initialize the manager with an integer resource value and provide different values for different screens (i.e. values-w600, values-large, values-land).

    0 讨论(0)
  • 2020-11-30 19:11
    public class AutoFitGridLayoutManager extends GridLayoutManager {
    
    private int columnWidth;
    private boolean columnWidthChanged = true;
    
    public AutoFitGridLayoutManager(Context context, int columnWidth) {
        super(context, 1);
    
        setColumnWidth(columnWidth);
    }
    
    
    public void setColumnWidth(int newColumnWidth) {
        if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
            columnWidth = newColumnWidth;
            columnWidthChanged = true;
        }
    }
    
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (columnWidthChanged && columnWidth > 0) {
            int totalSpace;
            if (getOrientation() == VERTICAL) {
                totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
            } else {
                totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();
            }
            int spanCount = Math.max(1, totalSpace / columnWidth);
            setSpanCount(spanCount);
            columnWidthChanged = false;
        }
        super.onLayoutChildren(recycler, state);
    }
    

    }

    now you can set LayoutManager to recycle view

    here i have set 250px

     AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 250);
     recycleView.setLayoutManager(layoutManager)
    

    show the belove image

    0 讨论(0)
  • 2020-11-30 19:11

    Constructor new GridLayoutManager(activity, 2) is about GridLayoutManager(Context context, int spanCount) where spanCount is the number of columns in the grid.

    Best way is to check window/view width and base on this width count how many spans you want to show.

    0 讨论(0)
  • 2020-11-30 19:13

    Set in recyclerView initialization:

    recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
    
    0 讨论(0)
  • 2020-11-30 19:21

    You can calculate available number of columns, given a desired column width, and load the image as calculated. Define a static funtion to calculate as:

    public class Utility {
        public static int calculateNoOfColumns(Context context, float columnWidthDp) { // For example columnWidthdp=180
            DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
            float screenWidthDp = displayMetrics.widthPixels / displayMetrics.density;
            int noOfColumns = (int) (screenWidthDp / columnWidthDp + 0.5); // +0.5 for correct rounding to int.
            return noOfColumns;
        }
    }
    

    And then when using it in the activity or fragment you can do like this :

    int mNoOfColumns = Utility.calculateNoOfColumns(getApplicationContext());
    
    ............
    mGridLayoutManager = new GridLayoutManager(this, mNoOfColumns);
    
    0 讨论(0)
  • 2020-11-30 19:30

    I tried @Riten answer and worked funtastic!! But I wasn't happy with the hardcoded "180" So I modified to this:

        public class ColumnQty {
        private int width, height, remaining;
        private DisplayMetrics displayMetrics;
    
        public ColumnQty(Context context, int viewId) {
    
            View view = View.inflate(context, viewId, null);
            view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
            width = view.getMeasuredWidth();
            height = view.getMeasuredHeight();
            displayMetrics = context.getResources().getDisplayMetrics();
        }
        public int calculateNoOfColumns() {
    
            int numberOfColumns = displayMetrics.widthPixels / width;
            remaining = displayMetrics.widthPixels - (numberOfColumns * width);
    //        System.out.println("\nRemaining\t" + remaining + "\nNumber Of Columns\t" + numberOfColumns);
            if (remaining / (2 * numberOfColumns) < 15) {
                numberOfColumns--;
                remaining = displayMetrics.widthPixels - (numberOfColumns * width);
            }
            return numberOfColumns;
        }
        public int calculateSpacing() {
    
            int numberOfColumns = calculateNoOfColumns();
    //        System.out.println("\nNumber Of Columns\t"+ numberOfColumns+"\nRemaining Space\t"+remaining+"\nSpacing\t"+remaining/(2*numberOfColumns)+"\nWidth\t"+width+"\nHeight\t"+height+"\nDisplay DPI\t"+displayMetrics.densityDpi+"\nDisplay Metrics Width\t"+displayMetrics.widthPixels);
            return remaining / (2 * numberOfColumns);
        }
    }
    

    Where "viewId" is the layout to be used as views in the RecyclerView like in R.layout.item_for_recycler

    Not sure though about the impact of View.inflate as I only use it to get the Width, nothing else.

    Then on the GridLayoutManager I do:

    GridLayoutManager gridLayoutManager = new GridLayoutManager(this, Utility.columnQty(this, R.layout.item_for_recycler));
    

    UPDATE: I added more lines to the code as I use it to get a minimum width spacing in the Grid. Calculate spacing:

    recyclerPatternsView.addItemDecoration(new GridSpacing(columnQty.calculateSpacing()));
    

    GridSpacing:

    public class GridSpacing extends RecyclerView.ItemDecoration {
        private final int spacing;
    
        public GridSpacing(int spacing) {
            this.spacing = spacing;
        }
    
        @Override
        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
            outRect.left = spacing;
            outRect.right = spacing;
            outRect.bottom = spacing;
            outRect.top = spacing;
        }
    }
    
    0 讨论(0)
提交回复
热议问题