首页 文章

如何使WRAP_CONTENT在RecyclerView上运行

提问于
浏览
162

我有 DialogFragment ,其中包含 RecyclerView (卡片列表) .

在这个 RecyclerView 中有一个或多个 CardViews 可以有任何高度 .

我想根据其中包含的 CardViews 给出 DialogFragment 正确的高度 .

通常情况下这很简单,我会像这样在 RecyclerView 上设置 wrap_content .

<android.support.v7.widget.RecyclerView ...
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"   
    android:clickable="true"   
    android:scrollbars="vertical" >

</android.support.v7.widget.RecyclerView>

因为我使用 RecyclerView 这不起作用,请参阅:

https://issuetracker.google.com/issues/37001674

Nested Recycler view height doesn't wrap its content

在这两个页面上,人们建议扩展 LinearLayoutManager 并覆盖 onMeasure()

我首先使用了第一个链接中提供的 LayoutManager

public static class WrappingLayoutManager extends LinearLayoutManager {

        public WrappingLayoutManager(Context context) {
            super(context);
        }

        private int[] mMeasuredDimension = 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);

            measureScrapChild(recycler, 0,
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);

            int width = mMeasuredDimension[0];
            int height = mMeasuredDimension[1];

            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                case View.MeasureSpec.AT_MOST:
                    width = widthSize;
                    break;
                case View.MeasureSpec.UNSPECIFIED:
            }

            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                case View.MeasureSpec.AT_MOST:
                    height = heightSize;
                    break;
                case View.MeasureSpec.UNSPECIFIED:
            }

            setMeasuredDimension(width, height);
        }

        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                       int heightSpec, int[] measuredDimension) {
            View view = recycler.getViewForPosition(position);
            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();
                measuredDimension[1] = view.getMeasuredHeight();
                recycler.recycleView(view);
            }
        }
    }

但是 this did not work 因为

heightSize = View.MeasureSpec.getSize(heightSpec);

返回一个非常大的值,看起来与 match_parent 有关 .

通过评论 height = heightSize; (在第二个开关的情况下)我设法使高度工作,但只有 CardView 内的 TextView 孩子不包装自己的文本(一个长句子) .

一旦 TextView 包裹它's own text the height SHOULD increase but it doesn' t . 它将该长句的高度计算为单行,而不是包裹行(2或更多) .

关于我应该如何改进这个 LayoutManager 的任何建议所以我的 RecyclerView 适用于 WRAP_CONTENT

Edit: This layout manager might work for most people, but it still has problems with scrolling and calculating heights of wrapping textviews

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = 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 width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

        if (getOrientation() == HORIZONTAL) {
            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        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;
            recycler.recycleView(view);
        }
    }
}

17 回答

  • 15

    Android Support Library 23.2.1更新,所有 WRAP_CONTENT 应该正常工作 .

    请更新 gradle 文件 OR 中的库版本以进一步:

    compile 'com.android.support:recyclerview-v7:23.2.1'
    

    解决了一些与各种测量规范方法相关的固定错误问题

    检查http://developer.android.com/tools/support-library/features.html#v7-recyclerview

    你可以查一下Support Library revision history

  • 1

    以下是该类的精炼版本,似乎有效,并且缺少其他解决方案的问题:

    package org.solovyev.android.views.llm;
    
    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    
    /**
     * {@link android.support.v7.widget.LinearLayoutManager} which wraps its content. Note that this class will always
     * wrap the content regardless of {@link android.support.v7.widget.RecyclerView} layout parameters.
     *
     * Now it's impossible to run add/remove animations with child views which have arbitrary dimensions (height for
     * VERTICAL orientation and width for HORIZONTAL). However if child views have fixed dimensions
     * {@link #setChildSize(int)} method might be used to let the layout manager know how big they are going to be.
     * If animations are not used at all then a normal measuring procedure will run and child views will be measured during
     * the measure pass.
     */
    public class LinearLayoutManager extends android.support.v7.widget.LinearLayoutManager {
    
        private static final int CHILD_WIDTH = 0;
        private static final int CHILD_HEIGHT = 1;
        private static final int DEFAULT_CHILD_SIZE = 100;
    
        private final int[] childDimensions = new int[2];
    
        private int childSize = DEFAULT_CHILD_SIZE;
        private boolean hasChildSize;
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(Context context) {
            super(context);
        }
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
        }
    
        public static int makeUnspecifiedSpec() {
            return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        }
    
        @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);
    
            final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
            final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;
    
            final int unspecified = makeUnspecifiedSpec();
    
            if (exactWidth && exactHeight) {
                // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
                super.onMeasure(recycler, state, widthSpec, heightSpec);
                return;
            }
    
            final boolean vertical = getOrientation() == VERTICAL;
    
            initChildDimensions(widthSize, heightSize, vertical);
    
            int width = 0;
            int height = 0;
    
            // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
            // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
            // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
            // called whiles scrolling)
            recycler.clear();
    
            final int stateItemCount = state.getItemCount();
            final int adapterItemCount = getItemCount();
            // adapter always contains actual data while state might contain old data (f.e. data before the animation is
            // done). As we want to measure the view with actual data we must use data from the adapter and not from  the
            // state
            for (int i = 0; i < adapterItemCount; i++) {
                if (vertical) {
                    if (!hasChildSize) {
                        if (i < stateItemCount) {
                            // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                            // we will use previously calculated dimensions
                            measureChild(recycler, i, widthSpec, unspecified, childDimensions);
                        } else {
                            logMeasureWarning(i);
                        }
                    }
                    height += childDimensions[CHILD_HEIGHT];
                    if (i == 0) {
                        width = childDimensions[CHILD_WIDTH];
                    }
                    if (height >= heightSize) {
                        break;
                    }
                } else {
                    if (!hasChildSize) {
                        if (i < stateItemCount) {
                            // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                            // we will use previously calculated dimensions
                            measureChild(recycler, i, unspecified, heightSpec, childDimensions);
                        } else {
                            logMeasureWarning(i);
                        }
                    }
                    width += childDimensions[CHILD_WIDTH];
                    if (i == 0) {
                        height = childDimensions[CHILD_HEIGHT];
                    }
                    if (width >= widthSize) {
                        break;
                    }
                }
            }
    
            if ((vertical && height < heightSize) || (!vertical && width < widthSize)) {
                // we really should wrap the contents of the view, let's do it
    
                if (exactWidth) {
                    width = widthSize;
                } else {
                    width += getPaddingLeft() + getPaddingRight();
                }
    
                if (exactHeight) {
                    height = heightSize;
                } else {
                    height += getPaddingTop() + getPaddingBottom();
                }
    
                setMeasuredDimension(width, height);
            } else {
                // if calculated height/width exceeds requested height/width let's use default "onMeasure" implementation
                super.onMeasure(recycler, state, widthSpec, heightSpec);
            }
        }
    
        private void logMeasureWarning(int child) {
            if (BuildConfig.DEBUG) {
                Log.w("LinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
                        "To remove this message either use #setChildSize() method or don't run RecyclerView animations");
            }
        }
    
        private void initChildDimensions(int width, int height, boolean vertical) {
            if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
                // already initialized, skipping
                return;
            }
            if (vertical) {
                childDimensions[CHILD_WIDTH] = width;
                childDimensions[CHILD_HEIGHT] = childSize;
            } else {
                childDimensions[CHILD_WIDTH] = childSize;
                childDimensions[CHILD_HEIGHT] = height;
            }
        }
    
        @Override
        public void setOrientation(int orientation) {
            // might be called before the constructor of this class is called
            //noinspection ConstantConditions
            if (childDimensions != null) {
                if (getOrientation() != orientation) {
                    childDimensions[CHILD_WIDTH] = 0;
                    childDimensions[CHILD_HEIGHT] = 0;
                }
            }
            super.setOrientation(orientation);
        }
    
        public void clearChildSize() {
            hasChildSize = false;
            setChildSize(DEFAULT_CHILD_SIZE);
        }
    
        public void setChildSize(int childSize) {
            hasChildSize = true;
            if (this.childSize != childSize) {
                this.childSize = childSize;
                requestLayout();
            }
        }
    
        private void measureChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] dimensions) {
            final View child = recycler.getViewForPosition(position);
    
            final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();
    
            final int hPadding = getPaddingLeft() + getPaddingRight();
            final int vPadding = getPaddingTop() + getPaddingBottom();
    
            final int hMargin = p.leftMargin + p.rightMargin;
            final int vMargin = p.topMargin + p.bottomMargin;
    
            final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
            final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);
    
            final int childWidthSpec = getChildMeasureSpec(widthSpec, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
            final int childHeightSpec = getChildMeasureSpec(heightSpec, vPadding + vMargin + vDecoration, p.height, canScrollVertically());
    
            child.measure(childWidthSpec, childHeightSpec);
    
            dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
            dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;
    
            recycler.recycleView(child);
        }
    }
    

    这也是library . 链接到relevant class .

  • 2

    终于找到了解决这个问题的方法 .

    您需要做的就是将 RecyclerView 包装在 RelativeLayout 中 . 也许还有其他观点可能也有效 .

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    
  • 2

    UPDATE

    通过Android支持库23.2更新,所有WRAP_CONTENT都应该正常工作 .

    请在gradle文件中更新库的版本 .

    compile 'com.android.support:recyclerview-v7:23.2.0'
    

    原始答案

    正如其他问题所解答的,当您的回收站视图高度大于屏幕高度时,您需要使用原始的onMeasure()方法 . 此布局管理器可以计算ItemDecoration并可以滚动更多 .

    public class MyLinearLayoutManager extends LinearLayoutManager {
    
    public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
        super(context, orientation, reverseLayout);
    }
    
    private int[] mMeasuredDimension = 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 width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {
            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);
    
            if (getOrientation() == HORIZONTAL) {
                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }
    
        // If child view is more than screen size, there is no need to make it wrap content. We can use original onMeasure() so we can scroll view.
        if (height < heightSize && width < widthSize) {
    
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        } else {
            super.onMeasure(recycler, state, widthSpec, heightSpec);
        }
    }
    
    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
    
       View view = recycler.getViewForPosition(position);
    
       // For adding Item Decor Insets to view
       super.measureChildWithMargins(view, 0, 0);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                        getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view), p.width);
                int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                        getPaddingTop() + getPaddingBottom() + getPaddingBottom() + getDecoratedBottom(view) , p.height);
                view.measure(childWidthSpec, childHeightSpec);
    
                // Get decorated measurements
                measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
                measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
                recycler.recycleView(view);
            }
        }
    }
    

    原始答案:https://stackoverflow.com/a/28510031/1577792

  • 9

    这是 c# version for mono android

    /* 
    * Ported by Jagadeesh Govindaraj (@jaganjan)
     *Copyright 2015 serso aka se.solovyev
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Contact details
     *
     * Email: se.solovyev @gmail.com
     * Site:  http://se.solovyev.org
     */
    
    
    using Android.Content;
    using Android.Graphics;
    using Android.Support.V4.View;
    using Android.Support.V7.Widget;
    using Android.Util;
    using Android.Views;
    using Java.Lang;
    using Java.Lang.Reflect;
    using System;
    using Math = Java.Lang.Math;
    
    namespace Droid.Helper
    {
        public class WrapLayoutManager : LinearLayoutManager
        {
            private const int DefaultChildSize = 100;
            private static readonly Rect TmpRect = new Rect();
            private int _childSize = DefaultChildSize;
            private static bool _canMakeInsetsDirty = true;
            private static readonly int[] ChildDimensions = new int[2];
            private const int ChildHeight = 1;
            private const int ChildWidth = 0;
            private static bool _hasChildSize;
            private static  Field InsetsDirtyField = null;
            private static int _overScrollMode = ViewCompat.OverScrollAlways;
            private static RecyclerView _view;
    
            public WrapLayoutManager(Context context, int orientation, bool reverseLayout)
                : base(context, orientation, reverseLayout)
            {
                _view = null;
            }
    
            public WrapLayoutManager(Context context) : base(context)
            {
                _view = null;
            }
    
            public WrapLayoutManager(RecyclerView view) : base(view.Context)
            {
                _view = view;
                _overScrollMode = ViewCompat.GetOverScrollMode(view);
            }
    
            public WrapLayoutManager(RecyclerView view, int orientation, bool reverseLayout)
                : base(view.Context, orientation, reverseLayout)
            {
                _view = view;
                _overScrollMode = ViewCompat.GetOverScrollMode(view);
            }
    
            public void SetOverScrollMode(int overScrollMode)
            {
                if (overScrollMode < ViewCompat.OverScrollAlways || overScrollMode > ViewCompat.OverScrollNever)
                    throw new ArgumentException("Unknown overscroll mode: " + overScrollMode);
                if (_view == null) throw new ArgumentNullException(nameof(_view));
                _overScrollMode = overScrollMode;
                ViewCompat.SetOverScrollMode(_view, overScrollMode);
            }
    
            public static int MakeUnspecifiedSpec()
            {
                return View.MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified);
            }
    
            public override void OnMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec,
                int heightSpec)
            {
                var widthMode = View.MeasureSpec.GetMode(widthSpec);
                var heightMode = View.MeasureSpec.GetMode(heightSpec);
    
                var widthSize = View.MeasureSpec.GetSize(widthSpec);
                var heightSize = View.MeasureSpec.GetSize(heightSpec);
    
                var hasWidthSize = widthMode != MeasureSpecMode.Unspecified;
                var hasHeightSize = heightMode != MeasureSpecMode.Unspecified;
    
                var exactWidth = widthMode == MeasureSpecMode.Exactly;
                var exactHeight = heightMode == MeasureSpecMode.Exactly;
    
                var unspecified = MakeUnspecifiedSpec();
    
                if (exactWidth && exactHeight)
                {
                    // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
                    base.OnMeasure(recycler, state, widthSpec, heightSpec);
                    return;
                }
    
                var vertical = Orientation == Vertical;
    
                InitChildDimensions(widthSize, heightSize, vertical);
    
                var width = 0;
                var height = 0;
    
                // it's possible to get scrap views in recycler which are bound to old (invalid) adapter
                // entities. This happens because their invalidation happens after "onMeasure" method.
                // As a workaround let's clear the recycler now (it should not cause any performance
                // issues while scrolling as "onMeasure" is never called whiles scrolling)
                recycler.Clear();
    
                var stateItemCount = state.ItemCount;
                var adapterItemCount = ItemCount;
                // adapter always contains actual data while state might contain old data (f.e. data
                // before the animation is done). As we want to measure the view with actual data we
                // must use data from the adapter and not from the state
                for (var i = 0; i < adapterItemCount; i++)
                {
                    if (vertical)
                    {
                        if (!_hasChildSize)
                        {
                            if (i < stateItemCount)
                            {
                                // we should not exceed state count, otherwise we'll get
                                // IndexOutOfBoundsException. For such items we will use previously
                                // calculated dimensions
                                MeasureChild(recycler, i, widthSize, unspecified, ChildDimensions);
                            }
                            else
                            {
                                LogMeasureWarning(i);
                            }
                        }
                        height += ChildDimensions[ChildHeight];
                        if (i == 0)
                        {
                            width = ChildDimensions[ChildWidth];
                        }
                        if (hasHeightSize && height >= heightSize)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (!_hasChildSize)
                        {
                            if (i < stateItemCount)
                            {
                                // we should not exceed state count, otherwise we'll get
                                // IndexOutOfBoundsException. For such items we will use previously
                                // calculated dimensions
                                MeasureChild(recycler, i, unspecified, heightSize, ChildDimensions);
                            }
                            else
                            {
                                LogMeasureWarning(i);
                            }
                        }
                        width += ChildDimensions[ChildWidth];
                        if (i == 0)
                        {
                            height = ChildDimensions[ChildHeight];
                        }
                        if (hasWidthSize && width >= widthSize)
                        {
                            break;
                        }
                    }
                }
    
                if (exactWidth)
                {
                    width = widthSize;
                }
                else
                {
                    width += PaddingLeft + PaddingRight;
                    if (hasWidthSize)
                    {
                        width = Math.Min(width, widthSize);
                    }
                }
    
                if (exactHeight)
                {
                    height = heightSize;
                }
                else
                {
                    height += PaddingTop + PaddingBottom;
                    if (hasHeightSize)
                    {
                        height = Math.Min(height, heightSize);
                    }
                }
    
                SetMeasuredDimension(width, height);
    
                if (_view == null || _overScrollMode != ViewCompat.OverScrollIfContentScrolls) return;
                var fit = (vertical && (!hasHeightSize || height < heightSize))
                          || (!vertical && (!hasWidthSize || width < widthSize));
    
                ViewCompat.SetOverScrollMode(_view, fit ? ViewCompat.OverScrollNever : ViewCompat.OverScrollAlways);
            }
    
            private void LogMeasureWarning(int child)
            {
    #if DEBUG
                Log.WriteLine(LogPriority.Warn, "LinearLayoutManager",
                    "Can't measure child #" + child + ", previously used dimensions will be reused." +
                    "To remove this message either use #SetChildSize() method or don't run RecyclerView animations");
    #endif
            }
    
            private void InitChildDimensions(int width, int height, bool vertical)
            {
                if (ChildDimensions[ChildWidth] != 0 || ChildDimensions[ChildHeight] != 0)
                {
                    // already initialized, skipping
                    return;
                }
                if (vertical)
                {
                    ChildDimensions[ChildWidth] = width;
                    ChildDimensions[ChildHeight] = _childSize;
                }
                else
                {
                    ChildDimensions[ChildWidth] = _childSize;
                    ChildDimensions[ChildHeight] = height;
                }
            }
    
            public void ClearChildSize()
            {
                _hasChildSize = false;
                SetChildSize(DefaultChildSize);
            }
    
            public void SetChildSize(int size)
            {
                _hasChildSize = true;
                if (_childSize == size) return;
                _childSize = size;
                RequestLayout();
            }
    
            private void MeasureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize,
                int[] dimensions)
            {
                View child = null;
                try
                {
                    child = recycler.GetViewForPosition(position);
                }
                catch (IndexOutOfRangeException e)
                {
                    Log.WriteLine(LogPriority.Warn, "LinearLayoutManager",
                        "LinearLayoutManager doesn't work well with animations. Consider switching them off", e);
                }
    
                if (child != null)
                {
                    var p = child.LayoutParameters.JavaCast<RecyclerView.LayoutParams>()
    
                    var hPadding = PaddingLeft + PaddingRight;
                    var vPadding = PaddingTop + PaddingBottom;
    
                    var hMargin = p.LeftMargin + p.RightMargin;
                    var vMargin = p.TopMargin + p.BottomMargin;
    
                    // we must make insets dirty in order calculateItemDecorationsForChild to work
                    MakeInsetsDirty(p);
                    // this method should be called before any getXxxDecorationXxx() methods
                    CalculateItemDecorationsForChild(child, TmpRect);
    
                    var hDecoration = GetRightDecorationWidth(child) + GetLeftDecorationWidth(child);
                    var vDecoration = GetTopDecorationHeight(child) + GetBottomDecorationHeight(child);
    
                    var childWidthSpec = GetChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.Width,
                        CanScrollHorizontally());
                    var childHeightSpec = GetChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.Height,
                        CanScrollVertically());
    
                    child.Measure(childWidthSpec, childHeightSpec);
    
                    dimensions[ChildWidth] = GetDecoratedMeasuredWidth(child) + p.LeftMargin + p.RightMargin;
                    dimensions[ChildHeight] = GetDecoratedMeasuredHeight(child) + p.BottomMargin + p.TopMargin;
    
                    // as view is recycled let's not keep old measured values
                    MakeInsetsDirty(p);
                }
                recycler.RecycleView(child);
            }
    
            private static void MakeInsetsDirty(RecyclerView.LayoutParams p)
            {
                if (!_canMakeInsetsDirty)
                {
                    return;
                }
                try
                {
                    if (InsetsDirtyField == null)
                    {
                       var klass = Java.Lang.Class.FromType (typeof (RecyclerView.LayoutParams));
                        InsetsDirtyField = klass.GetDeclaredField("mInsetsDirty");
                        InsetsDirtyField.Accessible = true;
                    }
                    InsetsDirtyField.Set(p, true);
                }
                catch (NoSuchFieldException e)
                {
                    OnMakeInsertDirtyFailed();
                }
                catch (IllegalAccessException e)
                {
                    OnMakeInsertDirtyFailed();
                }
            }
    
            private static void OnMakeInsertDirtyFailed()
            {
                _canMakeInsetsDirty = false;
    #if DEBUG
                Log.Warn("LinearLayoutManager",
                    "Can't make LayoutParams insets dirty, decorations measurements might be incorrect");
    #endif
            }
        }
    }
    
  • 1

    RecyclerView23.2.0 中添加了对 wrap_content 的支持,这是有缺陷的,23.2.1只是稳定的,所以你可以使用:

    compile 'com.android.support:recyclerview-v7:24.2.0'
    

    您可以在此处查看修订历史记录:

    https://developer.android.com/topic/libraries/support-library/revisions.html

    Note:

    另请注意,更新支持库后 RecyclerView 将尊重 wrap_content 以及 match_parent 所以如果您将 RecyclerView 的项目视图设置为 match_parent ,则单个视图将填满整个屏幕

  • -1

    滚动和文本换行的问题是此代码假设宽度和高度都设置为 wrap_content . 但是, LayoutManager 需要知道水平宽度受到约束 . 因此,不要为每个子视图创建自己的 widthSpec ,只需使用原始 widthSpec

    @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 width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {
            measureScrapChild(recycler, i,
                    widthSpec,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);
    
            if (getOrientation() == HORIZONTAL) {
                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }
        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }
    
        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }
    
        setMeasuredDimension(width, height);
    }
    
    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                        getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(widthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
    
  • 172

    试试这个(这是一个令人讨厌的解决方案,但它可能有效):在 ActivityonCreate 方法或片段的 onViewCreated 方法中 . 设置一个回调准备好在 RecyclerView 首次渲染时被触发,如下所示:

    vRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    calculeRecyclerViewFullHeight();
                }
            });
    

    calculeRecyclerViewFullHeight 中根据其子项的高度计算 RecyclerView 全高 .

    protected void calculateSwipeRefreshFullHeight() {
            int height = 0;
            for (int idx = 0; idx < getRecyclerView().getChildCount(); idx++ ) {
                View v = getRecyclerView().getChildAt(idx);
                height += v.getHeight();
            }
            SwipeRefreshLayout.LayoutParams params = getSwipeRefresh().getLayoutParams();
            params.height = height;
            getSwipeRefresh().setLayoutParams(params);
        }
    

    在我的情况下,我的 RecyclerView 包含在 SwipeRefreshLayout 中,因为我将高度设置为 SwipeRefreshView 而不是 RecyclerView 但是如果你没有任何 SwipeRefreshView 那么你可以将高度设置为 RecyclerView .

    如果这对你有帮助,请告诉我 .

  • 51

    这现在可以正常运行,因为他们已经在版本23.2中发布了一个版本,如post中所述 . 引用官方blogpost

    此版本为LayoutManager API带来了令人兴奋的新功能:自动测量!这允许RecyclerView根据其内容的大小调整自身大小 . 这意味着现在可以使用以前不可用的方案,例如使用WRAP_CONTENT作为RecyclerView的维度 . 您会发现所有内置的LayoutManagers现在都支持自动测量 .

  • 17

    而不是使用任何库,最简单的解决方案,直到新版本出来是打开b.android.com/74772 . 您可以轻松找到迄今为止已知的最佳解决方案 .

    PS:b.android.com/74772#c50为我工作

  • 0

    我使用了上面的一些解决方案,但它适用于 widthheight .

    • 如果你指定的 compileSdkVersion 大于 23 ,你可以直接使用 RecyclerView 在各自的Recycler视图支持库中提供,就像 23 那样 'com.android.support:recyclerview-v7:23.2.1' . 这些 support libraries 支持 wrap_content 属性的宽度和高度 .

    您必须将其添加到依赖项中

    compile 'com.android.support:recyclerview-v7:23.2.1'
    
    • 如果你的 compileSdkVersion 小于 23 ,你可以使用下面提到的解决方案 .

    关于这个问题我找到了Google thread . 在这个帖子中,有一个贡献导致LinearLayoutManager的实施 .

    I have tested it for both height and width and it worked fine for me in both cases.

    /*
     * Copyright 2015 serso aka se.solovyev
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *    http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Contact details
     *
     * Email: se.solovyev@gmail.com
     * Site:  http://se.solovyev.org
     */
    
    package org.solovyev.android.views.llm;
    
    import android.content.Context;
    import android.graphics.Rect;
    import android.support.v4.view.ViewCompat;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    
    import java.lang.reflect.Field;
    
    /**
     * {@link android.support.v7.widget.LinearLayoutManager} which wraps its content. Note that this class will always
     * wrap the content regardless of {@link android.support.v7.widget.RecyclerView} layout parameters.
     * <p/>
     * Now it's impossible to run add/remove animations with child views which have arbitrary dimensions (height for
     * VERTICAL orientation and width for HORIZONTAL). However if child views have fixed dimensions
     * {@link #setChildSize(int)} method might be used to let the layout manager know how big they are going to be.
     * If animations are not used at all then a normal measuring procedure will run and child views will be measured during
     * the measure pass.
     */
    public class LinearLayoutManager extends android.support.v7.widget.LinearLayoutManager {
    
        private static boolean canMakeInsetsDirty = true;
        private static Field insetsDirtyField = null;
    
        private static final int CHILD_WIDTH = 0;
        private static final int CHILD_HEIGHT = 1;
        private static final int DEFAULT_CHILD_SIZE = 100;
    
        private final int[] childDimensions = new int[2];
        private final RecyclerView view;
    
        private int childSize = DEFAULT_CHILD_SIZE;
        private boolean hasChildSize;
        private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS;
        private final Rect tmpRect = new Rect();
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(Context context) {
            super(context);
            this.view = null;
        }
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
            this.view = null;
        }
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(RecyclerView view) {
            super(view.getContext());
            this.view = view;
            this.overScrollMode = ViewCompat.getOverScrollMode(view);
        }
    
        @SuppressWarnings("UnusedDeclaration")
        public LinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) {
            super(view.getContext(), orientation, reverseLayout);
            this.view = view;
            this.overScrollMode = ViewCompat.getOverScrollMode(view);
        }
    
        public void setOverScrollMode(int overScrollMode) {
            if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER)
                throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode);
            if (this.view == null) throw new IllegalStateException("view == null");
            this.overScrollMode = overScrollMode;
            ViewCompat.setOverScrollMode(view, overScrollMode);
        }
    
        public static int makeUnspecifiedSpec() {
            return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        }
    
        @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);
    
            final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED;
            final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED;
    
            final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
            final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;
    
            final int unspecified = makeUnspecifiedSpec();
    
            if (exactWidth && exactHeight) {
                // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
                super.onMeasure(recycler, state, widthSpec, heightSpec);
                return;
            }
    
            final boolean vertical = getOrientation() == VERTICAL;
    
            initChildDimensions(widthSize, heightSize, vertical);
    
            int width = 0;
            int height = 0;
    
            // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
            // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
            // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
            // called whiles scrolling)
            recycler.clear();
    
            final int stateItemCount = state.getItemCount();
            final int adapterItemCount = getItemCount();
            // adapter always contains actual data while state might contain old data (f.e. data before the animation is
            // done). As we want to measure the view with actual data we must use data from the adapter and not from  the
            // state
            for (int i = 0; i < adapterItemCount; i++) {
                if (vertical) {
                    if (!hasChildSize) {
                        if (i < stateItemCount) {
                            // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                            // we will use previously calculated dimensions
                            measureChild(recycler, i, widthSize, unspecified, childDimensions);
                        } else {
                            logMeasureWarning(i);
                        }
                    }
                    height += childDimensions[CHILD_HEIGHT];
                    if (i == 0) {
                        width = childDimensions[CHILD_WIDTH];
                    }
                    if (hasHeightSize && height >= heightSize) {
                        break;
                    }
                } else {
                    if (!hasChildSize) {
                        if (i < stateItemCount) {
                            // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                            // we will use previously calculated dimensions
                            measureChild(recycler, i, unspecified, heightSize, childDimensions);
                        } else {
                            logMeasureWarning(i);
                        }
                    }
                    width += childDimensions[CHILD_WIDTH];
                    if (i == 0) {
                        height = childDimensions[CHILD_HEIGHT];
                    }
                    if (hasWidthSize && width >= widthSize) {
                        break;
                    }
                }
            }
    
            if (exactWidth) {
                width = widthSize;
            } else {
                width += getPaddingLeft() + getPaddingRight();
                if (hasWidthSize) {
                    width = Math.min(width, widthSize);
                }
            }
    
            if (exactHeight) {
                height = heightSize;
            } else {
                height += getPaddingTop() + getPaddingBottom();
                if (hasHeightSize) {
                    height = Math.min(height, heightSize);
                }
            }
    
            setMeasuredDimension(width, height);
    
            if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) {
                final boolean fit = (vertical && (!hasHeightSize || height < heightSize))
                        || (!vertical && (!hasWidthSize || width < widthSize));
    
                ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS);
            }
        }
    
        private void logMeasureWarning(int child) {
            if (BuildConfig.DEBUG) {
                Log.w("LinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
                        "To remove this message either use #setChildSize() method or don't run RecyclerView animations");
            }
        }
    
        private void initChildDimensions(int width, int height, boolean vertical) {
            if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
                // already initialized, skipping
                return;
            }
            if (vertical) {
                childDimensions[CHILD_WIDTH] = width;
                childDimensions[CHILD_HEIGHT] = childSize;
            } else {
                childDimensions[CHILD_WIDTH] = childSize;
                childDimensions[CHILD_HEIGHT] = height;
            }
        }
    
        @Override
        public void setOrientation(int orientation) {
            // might be called before the constructor of this class is called
            //noinspection ConstantConditions
            if (childDimensions != null) {
                if (getOrientation() != orientation) {
                    childDimensions[CHILD_WIDTH] = 0;
                    childDimensions[CHILD_HEIGHT] = 0;
                }
            }
            super.setOrientation(orientation);
        }
    
        public void clearChildSize() {
            hasChildSize = false;
            setChildSize(DEFAULT_CHILD_SIZE);
        }
    
        public void setChildSize(int childSize) {
            hasChildSize = true;
            if (this.childSize != childSize) {
                this.childSize = childSize;
                requestLayout();
            }
        }
    
        private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) {
            final View child;
            try {
                child = recycler.getViewForPosition(position);
            } catch (IndexOutOfBoundsException e) {
                if (BuildConfig.DEBUG) {
                    Log.w("LinearLayoutManager", "LinearLayoutManager doesn't work well with animations. Consider switching them off", e);
                }
                return;
            }
    
            final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();
    
            final int hPadding = getPaddingLeft() + getPaddingRight();
            final int vPadding = getPaddingTop() + getPaddingBottom();
    
            final int hMargin = p.leftMargin + p.rightMargin;
            final int vMargin = p.topMargin + p.bottomMargin;
    
            // we must make insets dirty in order calculateItemDecorationsForChild to work
            makeInsetsDirty(p);
            // this method should be called before any getXxxDecorationXxx() methods
            calculateItemDecorationsForChild(child, tmpRect);
    
            final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
            final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);
    
            final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
            final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically());
    
            child.measure(childWidthSpec, childHeightSpec);
    
            dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
            dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;
    
            // as view is recycled let's not keep old measured values
            makeInsetsDirty(p);
            recycler.recycleView(child);
        }
    
        private static void makeInsetsDirty(RecyclerView.LayoutParams p) {
            if (!canMakeInsetsDirty) {
                return;
            }
            try {
                if (insetsDirtyField == null) {
                    insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty");
                    insetsDirtyField.setAccessible(true);
                }
                insetsDirtyField.set(p, true);
            } catch (NoSuchFieldException e) {
                onMakeInsertDirtyFailed();
            } catch (IllegalAccessException e) {
                onMakeInsertDirtyFailed();
            }
        }
    
        private static void onMakeInsertDirtyFailed() {
            canMakeInsetsDirty = false;
            if (BuildConfig.DEBUG) {
                Log.w("LinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect");
            }
        }
    }
    
  • 2

    This comment helped me. Put the recyclerview in any other layout (Relative layout is preferable). Then change recyclerview's height/width as match parent to that layout and set the parent layout's height/width as wrap content.

  • 5

    替换 measureScrapChild 以遵循代码:

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
            int heightSpec, int[] measuredDimension)
        {
            View view = recycler.GetViewForPosition(position);
            if (view != null)
            {
                MeasureChildWithMargins(view, widthSpec, heightSpec);
                measuredDimension[0] = view.MeasuredWidth;
                measuredDimension[1] = view.MeasuredHeight;
                recycler.RecycleView(view);
            }
        }
    

    我使用xamarin,所以这是c#代码 . 我认为这可以很容易地“翻译”为Java .

  • 1

    在Adapter viewholder onCreateViewHolder方法中使用null值而不是父视图组更新视图 .

    @Override
    public AdapterItemSku.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    
        View view = inflator.inflate(R.layout.layout_item, null, false);
        return new MyViewHolder(view);
    }
    
  • 0

    您必须将FrameLayout作为主视图,然后使用ScrollView和至少您的RecyclerView放入RelativeLayout,它适用于我 .

    这里的真正诀窍是RelativeLayout ......

    乐于帮助 .

  • 0

    我建议你将recyclerview放在任何其他布局中(相对布局更可取) . 然后将recyclerview的高度/宽度更改为与该布局匹配的父级,并将父级布局的高度/宽度设置为换行内容 . 这个对我有用

  • 0

    我没有处理我的答案,但我知道它的方式StaggridLayoutManager没有 . 网格1可以解决您的问题,因为StaggridLayout会根据内容的大小自动调整其高度和宽度 . 如果它的工作不要忘记检查它是一个正确的答案 . 欢呼..

相关问题