首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >RecyclerView与GridLayoutManager试图解决wrap_content

RecyclerView与GridLayoutManager试图解决wrap_content
EN

Stack Overflow用户
提问于 2015-07-28 15:54:00
回答 3查看 10.3K关注 0票数 9

我试图解决以下问题:

  • 使用RecyclerView
  • 用GridLayoutManager
  • 有固定的细胞宽度
  • 回收视图仅调整到必要的高度(wrap_content)

我尝试使用以下代码,问题是它不能工作,而且我还没有找到任何工作示例,没有提到当方向发生变化时可以正确地重绘。

代码语言:javascript
运行
复制
public class AutofitRecyclerView extends RecyclerView {
    private MyGridLayoutManager manager;
    private int columnWidth = -1;

    public AutofitRecyclerView(Context context) {
        super(context);
        init(context, null);
    }

    public AutofitRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public AutofitRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            int[] attrsArray = {
                    android.R.attr.columnWidth
            };
            TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
            columnWidth = array.getDimensionPixelSize(0, -1);
            array.recycle();
        }

        manager = new MyGridLayoutManager(getContext(), 1);
        setLayoutManager(manager);
    }

    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);
        if (columnWidth > 0) {

            int mw = getMeasuredWidth();

            int spanCount = Math.max(1, mw / columnWidth);
            manager.setSpanCount(spanCount);
        }

        int numOfFullRows = manager.getItemCount() / manager.getSpanCount();

        if(manager.getItemCount() % manager.getSpanCount() > 0)
        {
            numOfFullRows++;
        }

        if(getChildCount() > 0) {
            int h = 0;
            try {
                h = manager.getChildAt(0).getMeasuredHeight();
            } catch (Exception e) {
                e.printStackTrace();
            }

            if(h != 0) {
                getLayoutParams().height = numOfFullRows * h;
            }
        }
    }
}
EN

回答 3

Stack Overflow用户

发布于 2015-12-11 14:33:35

基于连接器发布的代码,我提出了以下解决方案,该解决方案支持不同的行/列大小(尽管我承认没有对此进行测试),考虑到项装饰的大小,并正确处理不同的度量模式。

以下是代码:

代码语言:javascript
运行
复制
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

public class WrappableGridLayoutManager extends GridLayoutManager {

    public WrappableGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    private int[] measuredSize = new int[2];

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);

        int spanWidth = 0;
        int spanHeight = 0;

        int viewWidth = 0;
        int viewHeight = 0;

        int spanCount = getSpanCount();

        for (int i = 0; i < getItemCount(); i++) {

            measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredSize);

            if (i % spanCount == 0) {
                spanWidth = measuredSize[0];
                spanHeight = measuredSize[1];
            } else {
                if (getOrientation() == VERTICAL) {
                    spanWidth += measuredSize[0];
                    spanHeight = Math.max(spanHeight, measuredSize[1]);
                } else {
                    spanWidth = Math.max(spanWidth, measuredSize[0]);
                    spanHeight += measuredSize[1];
                }
            }

            if (i % spanCount == spanCount - 1 || i == getItemCount() - 1) {
                if (getOrientation() == VERTICAL) {
                    viewWidth = Math.max(viewWidth, spanWidth);
                    viewHeight += spanHeight;
                } else {
                    viewWidth += spanWidth;
                    viewHeight = Math.max(viewHeight, spanHeight);
                }
            }
        }

        int finalWidth;
        int finalHeight;

        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                finalWidth = widthSize;
                break;
            case View.MeasureSpec.AT_MOST:
                finalWidth = Math.min(widthSize, viewWidth);
                break;
            case View.MeasureSpec.UNSPECIFIED:
                finalWidth = viewWidth;
                break;
            default:
                finalWidth = widthSize;
                break;
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                finalHeight = heightSize;
                break;
            case View.MeasureSpec.AT_MOST:
                finalHeight = Math.min(heightSize, viewHeight);
                break;
            case View.MeasureSpec.UNSPECIFIED:
                finalHeight = viewHeight;
                break;
            default:
                finalHeight = heightSize;
                break;
        }

        setMeasuredDimension(finalWidth, finalHeight);
    }


    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) {

        View view = null;
        try {
            view = recycler.getViewForPosition(position);
        } catch (Exception ex) {
          // try - catch is needed since support library version 24
        }


        if (view != null) {

            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();

            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height);

            view.measure(childWidthSpec, childHeightSpec);

            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;

            Rect decoratorRect = new Rect();
            calculateItemDecorationsForChild(view, decoratorRect);
            measuredDimension[0] += decoratorRect.left;
            measuredDimension[0] += decoratorRect.right;
            measuredDimension[1] += decoratorRect.top;
            measuredDimension[1] += decoratorRect.bottom;

            recycler.recycleView(view);
        }
    }
}
票数 10
EN

Stack Overflow用户

发布于 2015-09-11 14:55:51

您需要添加一个自定义GridlayoutManager。检查这个https://gist.github.com/ArthurSav/5f80e19d9ba6d562fbd5

票数 7
EN

Stack Overflow用户

发布于 2020-10-14 23:16:19

谢谢@nantoka@arthur的代码,这给了我一个好的开始。不幸的是,它在不同的spanCount中不能很好地工作,所以我这里是我的更新(Kotlin):

代码语言:javascript
运行
复制
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Recycler
import com.baziliqo.app.bar.utils.takeIfInstance

class WrappableGridLayoutManager(context: Context?, val preferedSpanCount: Int, @RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL) :
    GridLayoutManager(context, preferedSpanCount, orientation, false) {

    private val mMeasuredDimension = IntArray(2)

    var measuredWidth = 0
    var measuredHeight = 0


    override fun onMeasure(recycler: Recycler, state: RecyclerView.State, widthSpec: Int, heightSpec: Int) {
        val suitableSpanCount = preferedSpanCount.coerceAtMost(itemCount)
        if (spanCount != suitableSpanCount) {
            spanCount = suitableSpanCount
            return
        }
        val widthMode = View.MeasureSpec.getMode(widthSpec)
        val heightMode = View.MeasureSpec.getMode(heightSpec)
        val widthSize = View.MeasureSpec.getSize(widthSpec)
        val heightSize = View.MeasureSpec.getSize(heightSpec)
        measuredWidth = 0
        measuredHeight = 0
        for (i in 0 until itemCount) {
            measureScrapChild(
                recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension
            )
            if (orientation == HORIZONTAL) {
                if (i % spanCount == 0) {
                    measuredWidth += mMeasuredDimension[0]
                }
                if (i < spanCount) {
                    measuredHeight += mMeasuredDimension[1]
                }
            } else {
                if (i % spanCount == 0) {
                    measuredHeight += mMeasuredDimension[1]
                }
                if (i < spanCount) {
                    measuredWidth += mMeasuredDimension[0]
                }
            }
        }
        when (widthMode) {
            View.MeasureSpec.EXACTLY -> measuredWidth = widthSize
            View.MeasureSpec.AT_MOST, View.MeasureSpec.UNSPECIFIED -> {
            }
        }
        when (heightMode) {
            View.MeasureSpec.EXACTLY -> measuredHeight = heightSize
            View.MeasureSpec.AT_MOST, View.MeasureSpec.UNSPECIFIED -> {
            }
        }
        setMeasuredDimension(measuredWidth, measuredHeight)
    }

    private fun measureScrapChild(recycler: Recycler, position: Int, widthSpec: Int, heightSpec: Int, measuredDimension: IntArray) {
        try {
            var view = recycler.getViewForPosition(position) ?: return
            val p = view.layoutParams as RecyclerView.LayoutParams
            val childWidthSpec = ViewGroup.getChildMeasureSpec(
                widthSpec,
                paddingLeft + paddingRight, p.width
            )
            val childHeightSpec = ViewGroup.getChildMeasureSpec(
                heightSpec,
                paddingTop + paddingBottom, p.height
            )
            view.measure(childWidthSpec, childHeightSpec)
            measuredDimension[0] = view.measuredWidth + p.leftMargin + p.rightMargin
            measuredDimension[1] = view.measuredHeight + p.bottomMargin + p.topMargin
            recycler.recycleView(view)
        } catch (e: Exception) {
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31681394

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档