How to force GridView to generate square cells in

2020-02-16 12:43发布

问题:

How can I force an android GridView to generate square cells (Cell's height equal to cell's width) GridView has 10*9 cells and the app must support multiple screens !

I used a Linear Layout:

row_grid.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="0dp" >

        <ImageView
            android:id="@+id/item_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/ic_launcher" >
        </ImageView>

    </LinearLayout>

and GridView: activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/katy" >

    <GridView
        android:id="@+id/gridView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:horizontalSpacing="0dp"
        android:numColumns="4"
        android:stretchMode="columnWidth"
        android:verticalSpacing="0dp" >
    </GridView>
</RelativeLayout>

Each cell of GridView contains a image that has same width and height. images are larger than cells and must stretch to fit in cells.

回答1:

First, you're going to want to create a custom View class that you can use instead of the default LinearLayout you're using. Then you want to override the View's onMeasure call, and force it to be square:

public class GridViewItem extends ImageView {

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

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

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

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec); // This is the key that will make the height equivalent to its width
    }
}

Then you can change your row_grid.xml file to:

<path.to.item.GridViewItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:src="@drawable/ic_launcher" >
</path.to.item.GridViewItem>

Just be sure to change "path.to.item" to the package where your GridViewItem.java class resides.

I also removed your LinearLayout parent since it wasn't doing anything for you there.

Edit:

Also changed scaleType from fitXY to centerCrop so that your image doesn't stretch itself and maintains its aspect ratio. And, as long as it's a square image, nothing should be cropped, regardless.



回答2:

You can Override your linear layout

public class MyLinearLayout extends LinearLayout {
    public MyLinearLayout(Context context) {
        super(context);
    }

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

    public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec); // This is the key that will make the height equivalent to its width
    }
}

then use it in the item_grid.xml

<?xml version="1.0" encoding="utf-8"?>
<com.example.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/item_grid"

    android:layout_margin="2dp"
    android:padding="3dp"
    android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Category Name"
        android:textStyle="bold"
        android:textColor="@color/colorPrimary"
        android:id="@+id/tvCategoryName" />


</com.example.MyLinearLayout>


回答3:

Works nicely, thank you! A small improvement I required would be always pick the smaller value, to prevent overshooting the screen:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if(heightMeasureSpec < widthMeasureSpec) {
        super.onMeasure(heightMeasureSpec, heightMeasureSpec);
    } else if(widthMeasureSpec < heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    } else {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

}


回答4:

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

public class GridViewItem extends RelativeLayout {

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

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

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

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec); // This is the key that will make the height equivalent to its width
    }
}

If your grid item just have an image then the answer is very good. But you want to add multiple items in your grid view then you must create Your Custom GridViewItem extending the layout you want your grid item to be. For example in my case I had RelativeLayout as the parent view so I created GridViewItem extending the RelativeLayout and it worked flawlessly.



回答5:

Just make sure that your images are square. And make the container wrap_content.