Wysokość widoku siatki zostanie zmniejszona

124

Próbuję wyświetlić 8 elementów w widoku siatki. Niestety wysokość widoku siatki jest zawsze za mała, więc pokazuje tylko pierwszy wiersz i niewielką część drugiego.

Ustawienie android:layout_height="300dp"sprawia, że ​​to działa. wrap_ contenti fill_parentnajwyraźniej nie.

Mój widok siatki:

<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" />

Moje przedmioty:

<?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>

Wydaje się, że problem nie jest związany z brakiem przestrzeni w pionie.

Co mogę zrobić ?

tacone
źródło

Odpowiedzi:

351

Po (zbyt wielu) badaniach natknąłem się na doskonałą odpowiedź Neila Trafta .

Dostosowanie jego pracy do tego GridViewbyło niezwykle łatwe.

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;
    }
}

Uwzględnij go w swoim układzie w następujący sposób:

<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" />

Na koniec wystarczy poprosić go o rozszerzenie:

mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
tacone
źródło
20
to rozwiązanie nie jest wydajne pod względem pamięci i aplikacja ulegnie awarii, jeśli komórki są obrazami. To rozwiązanie informuje widok przewijania, jaka jest wysokość pełnego widoku siatki, aby mógł spaść, ale problem polega na tym, że aby to zrobić, renderuje wszystko bez użycia recyklingu. Nie mogło działać więcej niż 200 elementów.
Mariano Latorre
7
@adamp Myślę, że są do tego przydatne przypadki. Jeśli masz ograniczoną liczbę elementów do wyświetlenia w tablicy 2D, użycie tego rodzaju widoku GridView wydaje się łatwiejsze niż próba utworzenia niestandardowego / dynamicznego układu TableLayout, prawda?
greg7gkb
5
Nie działa dla mnie, umieściłem ExpandableHeightGridView pod ScrollView, wycina ostatni widok.
Chirag Nagariya
3
@tacone Istnieje wiele lepszych rozwiązań tego rodzaju łatwo dostępnych we frameworku, bibliotece obsługującej i innym otwartym kodzie źródłowym w Internecie, z których najłatwiejszym może być proste pobieranie widoków w pętli for z adaptera lub gdzie indziej i dodanie ich do GridLayout (nie GridView; GridLayout jest również dostępna w bibliotece pomocy technicznej) TableLayout lub podobnej.
adamp
11
@adamp Jeśli to nie jest dobre, dodaj w odpowiedzi najlepsze rozwiązanie, jakie możesz wymyślić
aleb
34

Po skorzystaniu z odpowiedzi z @tacone i upewnieniu się, że działa, postanowiłem skrócić kod. To jest mój wynik. PS: Jest to równoważne z ustawieniem wartości logicznej „rozszerzonej” w tonach odpowiedzi zawsze na prawdę.

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();
    }
}
Jacob R.
źródło
Ale poczekaj - to nadal boryka się z problemem wykorzystania pamięci; nie recyklingujesz już, prawda?
Fattie
6

Innym podobnym podejściem, które zadziałało w moim przypadku, jest obliczenie wysokości dla jednego wiersza, a następnie za pomocą danych statycznych (można je dostosować do podziału na strony) można obliczyć liczbę posiadanych wierszy i łatwo zmienić rozmiar widoku 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);
}

Użyj tego kodu po ustawieniu karty i podczas rysowania widoku GridView lub uzyskasz wysokość = 0.

gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!gridViewResized) {
                    gridViewResized = true;
                    resizeGridView(gridView, numItems, numColumns);
                }
            }
        });
Pelanes
źródło
1
To zadziałało dobrze - używam kilku GridViews wewnątrz ListView. Nie jestem pewien, czy to jeszcze zły pomysł, czy nie - musisz zbadać wydajność przy użyciu dużego zbioru danych. Ale niezależnie od tego, dzięki za kod. Myślę jednak, że jest jeden błąd - musiałem użyćint rows = items / columns + 1;
Andrew
poniżej Android OS 5.0 java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
pojawia
ViewGroup.LayoutParams params = gridView.getLayoutParams (); zgłasza wyjątek NullPointerException
Luke Allison
4

Znaleziono odpowiedzi na tacones helpfull ... więc przeportowałem go do 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);    
        }
    }
}
spaceMonster
źródło
1
Kudos stary. Działa świetnie w xamarin.android
Suchith
0

Wystarczy obliczyć wysokość dla AT_MOST i ustawić na miarę. Tutaj GridView Scroll nie będzie działać. Trzeba jawnie używać widoku przewijania w pionie.

 @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);
 }
Uday Sravan K.
źródło
Czy ta metoda pomaga uzyskać przewijanie dla GridView
Suchith