Gridview高度被削减

Posted

技术标签:

【中文标题】Gridview高度被削减【英文标题】:Gridview height gets cut 【发布时间】:2012-01-18 21:23:32 【问题描述】:

我正在尝试在 gridview 中显示 8 个项目。可悲的是,gridview 的高度总是太小,所以它只显示第一行,第二行的一小部分。

设置android:layout_height="300dp" 使其工作。 wrap_contentfill_parent 显然不是。

我的网格视图:

<GridView
    android:id="@+id/myId"
    android:layout_
    android:layout_
    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_
    android:layout_
    android:orientation="vertical"
    android:minHeight="?android:attr/listPreferredItemHeight" >

    <ImageView
        android:id="@+id/appItemIcon"
        android:layout_
        android:layout_
        android:src="@android:drawable/ic_dialog_info"
        android:scaleType="center" />      

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

</LinearLayout>

这个问题似乎与缺乏垂直空间无关。

我能做什么?

【问题讨论】:

这能回答你的问题吗? How to have a GridView that adapts its height when items are added 【参考方案1】:

经过(太多)研究,我偶然发现了the excellent answer of 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_
    android:layout_
    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);

【讨论】:

此解决方案的内存效率不高,如果单元格是图像,应用程序将崩溃。这个解决方案告诉滚动视图完整的网格视图的高度是多少,所以它可以下降,但问题是这样做会渲染所有内容而不使用回收。不能超过 200 个项目。 @adamp 我认为这有一些有用的案例。如果要显示到二维数组中的项目数量有限,使用这种 GridView 似乎比尝试创建某种自定义/动态 TableLayout 更容易,不是吗? 不适用于我,我已将 ExpandableHeightGridView 放在 ScrollView 下,它会剪切最后一个视图。 @tacone 框架、支持库和网络上的其他开源代码中现成的这类问题有许多更好的解决方案,其中最简单的可以是简单的 for 循环从适配器或其他地方拉取视图并将它们添加到 GridLayout,(不是 GridView;GridLayout 在支持库中也可用)TableLayout 或类似的。 @adamp 如果这不好,请用您能想到的最佳解决方案添加您的答案【参考方案2】:

使用@tacone 的答案并确保它有效后,我决定尝试缩短代码。这是我的结果。 PS:这相当于将 tacones 答案中的布尔“扩展”始终设置为 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();
    

【讨论】:

但是等等 - 这仍然存在内存使用问题;你不再回收了,对吧?【参考方案3】:

另一种对我有用的类似方法是计算一行的高度,然后使用静态数据(您可以将其调整为分页),您可以计算您拥有的行数并轻松调整 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);
                
            
        );

【讨论】:

这对我来说效果很好——我在 ListView 中使用了一堆 GridView。不确定这是否是一个坏主意 - 需要使用大型数据集调查性能。但无论如何,感谢您的代码。我认为有一个错误-我不得不使用int rows = items / columns + 1; 对于低于 android os 5.0 我收到此错误java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams ViewGroup.LayoutParams 参数 = gridView.getLayoutParams();抛出 NullPointerException【参考方案4】:

发现 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);    
        
    

【讨论】:

感谢老兄。在 xamarin.android 中效果很好【参考方案5】:

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(所有行都可见),正如预期的那样。

【讨论】:

【参考方案6】:

只需计算 AT_MOST 的高度并设置为 on measure。此处 GridView Scroll 将无法正常工作。需要显式使用 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

以上是关于Gridview高度被削减的主要内容,如果未能解决你的问题,请参考以下文章

Android动态设定GridView的高度,固定column,实现高度自适应

android设置GridView高度自适应,实现全屏铺满效果

GridView动态计算高度

Flutter 设置Container高度自适应GridView 或Listview

为啥 GridView.builder 返回高度扩展的元素,而 ListView.Seperated 返回具有正常高度的元素?

GridView的使用(高度封装,不怎么灵活,repeat可替代)