GridView高度被裁剪

127

我试图在网格视图中显示8个项目。不幸的是,网格视图的高度总是太低,只显示第一行和第二行的一小部分。

设置android:layout_height="300dp"可以解决问题,但是wrap_contentfill_parent似乎都不行。

我的网格视图:

<GridView
    android:id="@+id/myId"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:horizontalSpacing="2dp"
    android:isScrollContainer="false"
    android:numColumns="4"
    android:stretchMode="columnWidth"
    android:verticalSpacing="20dp" />

我的项目资源:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:minHeight="?android:attr/listPreferredItemHeight" >

    <ImageView
        android:id="@+id/appItemIcon"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_dialog_info"
        android:scaleType="center" />      

    <TextView
        android:id="@+id/appItemText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="My long application name"
        android:gravity="center_horizontal"
        android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>

这个问题似乎与垂直空间不足无关。

我该怎么办?


这个回答解决了你的问题吗?如何在添加项目时使GridView自适应其高度 - Shivam Agarwal
6个回答

361

经过(太多)研究,我偶然发现了Neil Traft的优秀答案

将他的工作适应于GridView非常容易。

ExpandableHeightGridView.java:

package com.example;
public class ExpandableHeightGridView extends GridView
{

    boolean expanded = false;

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

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

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

    public boolean isExpanded()
    {
        return expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // HACK! TAKE THAT ANDROID!
        if (isExpanded())
        {
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
                    MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);

            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        }
        else
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void setExpanded(boolean expanded)
    {
        this.expanded = expanded;
    }
}

像这样将其包含在布局中:

<com.example.ExpandableHeightGridView
    android:id="@+id/myId"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:horizontalSpacing="2dp"
    android:isScrollContainer="false"
    android:numColumns="4"
    android:stretchMode="columnWidth"
    android:verticalSpacing="20dp" />

最后,您只需要要求它进行扩展:
mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);

23
这个解决方案的内存使用效率不高,如果单元格是图像,应用程序将会崩溃。这个解决方案告诉滚动视图完整网格视图的高度,以便它可以向下滚动,但问题是为了做到这一点,它会渲染所有内容而不使用回收。最多只能处理200个项目。 - Mariano Latorre
8
我觉得这样做有一些有用的情况。如果你需要显示有限数量的项目到一个二维数组中,使用这种类型的GridView似乎比尝试创建某种自定义/动态的TableLayout更容易,不是吗? - greg7gkb
7
对我没有用,我已经把ExpandableHeightGridView放在ScrollView下面,但它会裁剪最后一个视图。 - Chirag Nagariya
3
这种问题有很多更好的解决方案可以在框架、支持库和其他开源代码中轻松找到,其中最简单的方法之一是使用 for 循环从适配器或其他位置提取 View,并将它们添加到 GridLayout(而不是 GridView;GridLayout 也可在支持库中找到)、TableLayout 或类似的布局中。 - adamp
13
好的,我会尽力按照要求进行翻译。以下是需要翻译的内容:@adamp 如果这不够好,请您提出您认为最好的解决方案。 - aleb
显示剩余25条评论

35

使用@tacone的答案并确保它起作用后,我决定尝试缩短代码。这是我的结果。PS:它相当于始终将tacone答案中的布尔值“扩展”设置为true。

public class StaticGridView extends GridView {

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

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

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

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
        getLayoutParams().height = getMeasuredHeight();
    }
}

1
但是等等 - 这仍然存在内存使用问题; 你不再进行回收了,对吧? - Fattie

6
另一种类似的方法适用于我,即先计算出一行的高度,然后使用静态数据(你可以将其适应分页)来计算有多少行,从而轻松调整GridView的高度。
    private void resizeGridView(GridView gridView, int items, int columns) {
    ViewGroup.LayoutParams params = gridView.getLayoutParams();
    int oneRowHeight = gridView.getHeight();
    int rows = (int) (items / columns);
    params.height = oneRowHeight * rows;
    gridView.setLayoutParams(params);
}

在设置适配器后,在 GridView 绘制时使用此代码,否则将得到高度为 0。
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!gridViewResized) {
                    gridViewResized = true;
                    resizeGridView(gridView, numItems, numColumns);
                }
            }
        });

1
这对我很有效 - 我在ListView中使用了一堆GridView。还不确定这是否是个好主意 - 需要研究大数据集的性能。但无论如何,感谢您提供的代码。不过我认为有一个偏移量错误 - 我不得不使用 int rows = items / columns + 1; - Andrew
对于Android操作系统5.0以下版本,我遇到了这个错误:java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams无法转换为android.widget.AbsListView$LayoutParams - silverFoxA
ViewGroup.LayoutParams params = gridView.getLayoutParams(); 抛出了一个空指针异常。 - Luke Allison

5

发现tacones的答案很有帮助...所以我将其移植到了C#(Xamarin)

public class ExpandableHeightGridView: GridView
{
    bool _isExpanded = false;

    public ExpandableHeightGridView(Context context) : base(context)
    {            
    }

    public ExpandableHeightGridView(Context context, IAttributeSet attrs) : base(context, attrs)
    {            
    }

    public ExpandableHeightGridView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
    {            
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }

        set { _isExpanded = value;  }
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // HACK! TAKE THAT ANDROID!
        if (IsExpanded)
        {
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.MakeMeasureSpec( View.MeasuredSizeMask, MeasureSpecMode.AtMost);
            base.OnMeasure(widthMeasureSpec,expandSpec);                

            var layoutParameters = this.LayoutParameters;
            layoutParameters.Height = this.MeasuredHeight;
        }
        else
        {
            base.OnMeasure(widthMeasureSpec,heightMeasureSpec);    
        }
    }
}

1
干得好,伙计。在Xamarin.Android中运行得非常好。 - Suchith

1

Jacob R 在 Kotlin 中的解决方案:

class ExpandableHeightGridView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : GridView(context, attrs, defStyleAttr) {

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
            MeasureSpec.AT_MOST)
        super.onMeasure(widthMeasureSpec, expandSpec)
        layoutParams.height = measuredHeight
    }
}

在将GridView添加到RecyclerView后,我得到了一个全尺寸的GridView(所有行都可见),正如预期的那样。


0

只需计算 AT_MOST 的高度并在测量时将其设置为 on。这里 GridView 滚动不起作用,需要显式使用 Vertical Scroll View。

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     int heightSpec;

     if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {

         heightSpec = MeasureSpec.makeMeasureSpec(
                        Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
     }
     else {
         // Any other height should be respected as is.
         heightSpec = heightMeasureSpec;
     }

     super.onMeasure(widthMeasureSpec, heightSpec);
 }

这个方法能帮助你实现 GridView 的滚动吗? - Suchith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接