RecyclerView GridLayoutManager: how to auto-detect span count?

后端 未结 13 561
没有蜡笔的小新
没有蜡笔的小新 2020-11-28 18:45

Using the new GridLayoutManager: https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html

It takes an explicit span count, so the pro

相关标签:
13条回答
  • 2020-11-28 18:48

    The upvoted solution is fine, but handles the incoming values as pixels, which can trip you up if you're hardcoding values for testing and assuming dp. Easiest way is probably to put the column width in a dimension and read it when configuring the GridAutofitLayoutManager, which will automatically convert dp to correct pixel value:

    new GridAutofitLayoutManager(getActivity(), (int)getActivity().getResources().getDimension(R.dimen.card_width))
    
    0 讨论(0)
  • 2020-11-28 18:48
    1. Set minimal fixed width of imageView (144dp x 144dp for example)
    2. When you create GridLayoutManager, you need to know how much columns will be with minimal size of imageView:

      WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); //Получаем размер экрана
      Display display = wm.getDefaultDisplay();
      
      Point point = new Point();
      display.getSize(point);
      int screenWidth = point.x; //Ширина экрана
      
      int photoWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 144, this.getResources().getDisplayMetrics()); //Переводим в точки
      
      int columnsCount = screenWidth/photoWidth; //Число столбцов
      
      GridLayoutManager gridLayoutManager = new GridLayoutManager(this, columnsCount);
      recyclerView.setLayoutManager(gridLayoutManager);
      
    3. After that you need to resize imageView in adapter if you have space in column. You may send newImageViewSize then inisilize adapter from activity there you calculate screen and column count:

      @Override //Заполнение нашей плитки
      public void onBindViewHolder(PhotoHolder holder, int position) {
         ...
         ViewGroup.LayoutParams photoParams = holder.photo.getLayoutParams(); //Параметры нашей фотографии
      
         int newImageViewSize = screenWidth/columnsCount; //Новый размер фотографии
      
         photoParams.width = newImageViewSize; //Установка нового размера
         photoParams.height = newImageViewSize;
         holder.photo.setLayoutParams(photoParams); //Установка параметров
         ...
      }
      

    It works in both orientations. In vertical I have 2 columns and in horizontal - 4 columns. The result: https://i.stack.imgur.com/WHvyD.jpg

    0 讨论(0)
  • 2020-11-28 18:49

    I'm posting this just in case someone gets weird column width as in my case.

    I'm not able to comment on @s-marks's answer due to my low reputation. I applied his solution solution but I got some weird column width, so I modified checkedColumnWidth function as follows:

    private int checkedColumnWidth(Context context, int columnWidth)
    {
        if (columnWidth <= 0)
        {
            /* Set default columnWidth value (48dp here). It is better to move this constant
            to static constant on top, but we need context to convert it to dp, so can't really
            do so. */
            columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
                    context.getResources().getDisplayMetrics());
        }
    
        else
        {
            columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, columnWidth,
                    context.getResources().getDisplayMetrics());
        }
        return columnWidth;
    }
    

    By converting the given column width into DP fixed the issue.

    0 讨论(0)
  • 2020-11-28 18:49

    To accommodate orientation change on s-marks's answer, I added a check on width change (width from getWidth(), not column width).

    private boolean mWidthChanged = true;
    private int mWidth;
    
    
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
    {
        int width = getWidth();
        int height = getHeight();
    
        if (width != mWidth) {
            mWidthChanged = true;
            mWidth = width;
        }
    
        if (mColumnWidthChanged && mColumnWidth > 0 && width > 0 && height > 0
                || mWidthChanged)
        {
            int totalSpace;
            if (getOrientation() == VERTICAL)
            {
                totalSpace = width - getPaddingRight() - getPaddingLeft();
            }
            else
            {
                totalSpace = height - getPaddingTop() - getPaddingBottom();
            }
            int spanCount = Math.max(1, totalSpace / mColumnWidth);
            setSpanCount(spanCount);
            mColumnWidthChanged = false;
            mWidthChanged = false;
        }
        super.onLayoutChildren(recycler, state);
    }
    
    0 讨论(0)
  • 2020-11-28 18:50

    Well, this is what I used, fairly basic, but gets the job done for me. This code basically gets the screen width in dips and then divides by 300 (or whatever width you're using for your adapter's layout). So smaller phones with 300-500 dip width only display one column, tablets 2-3 columns etc. Simple, fuss free and without downside, as far as I can see.

    Display display = getActivity().getWindowManager().getDefaultDisplay();
    DisplayMetrics outMetrics = new DisplayMetrics();
    display.getMetrics(outMetrics);
    
    float density  = getResources().getDisplayMetrics().density;
    float dpWidth  = outMetrics.widthPixels / density;
    int columns = Math.round(dpWidth/300);
    mLayoutManager = new GridLayoutManager(getActivity(),columns);
    mRecyclerView.setLayoutManager(mLayoutManager);
    
    0 讨论(0)
  • 2020-11-28 18:50

    I conclusion above answers here

    0 讨论(0)
提交回复
热议问题