如何强制Android中的GridView生成正方形单元格

33

如何强制 Android GridView 生成正方形单元格(单元格的高度等于单元格的宽度)?GridView 有 10 * 9 个单元格,应用程序必须支持多个屏幕!

我使用了线性布局:

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>

以及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>

GridView中的每个单元格都包含一个具有相同宽度和高度的图像。图像比单元格大,必须拉伸以适应单元格。 输入图片说明

6个回答

100

首先,您需要创建一个自定义的View类,以便可以在使用默认的LinearLayout之前使用它。 然后,您希望重写View的onMeasure调用,并强制其成为正方形:


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

那么您可以更改row_grid.xml文件如下:

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

请确保将"path.to.item"更改为您的GridViewItem.java类所在的包。

我还删除了您的LinearLayout父级,因为它对您没有任何帮助。

编辑:

还将scaleType从fitXY更改为centerCrop,以使图像不会拉伸并保持其纵横比。 只要是正方形图像,就不应该裁剪任何内容。


谢谢,但是发生了运行时错误!'android.view.InflateException: Binary XML file line #1: Error inflating class com.example.test.GridViewItem' 包下载链接:http://s000.tinyupload.com/index.php?file_id=90216865398945988480 - Jessica
@Jessica,你的GridViewItem.java类不在XML中指定的包中,这就是为什么它无法膨胀的原因。你应该将它移动到正确的包中,这样它就可以正常工作了。 - Cruceo
如果您的网格项只有一个图像视图,则答案可以完美地工作。如果您希望您的网格项是ViewGroup而不是ImageView,请查看此答案(https://dev59.com/emAf5IYBdhLWcg3wqEHp#57232928)。 - Jain

14

你可以覆盖你的线性布局

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

然后在 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>

9

使用 ConstraintLayout 如何?

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:padding="3dp">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

3

非常好,谢谢!我需要进行一些小的改进,即始终选择较小的值,以防止超出屏幕:

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

}

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

如果你的网格项目只有一张图片,那么 answer 是非常好的选择。但如果你想要在你的网格项中添加多个元素,那么你必须创建自定义的GridViewItem来扩展你想要的网格项布局。例如,在我的例子中,我将RelativeLayout作为父视图,所以我创建了一个扩展了RelativeLayout的GridViewItem,而且它运行得非常流畅。

这与@Cruceo的答案有何不同? - Amir Dora.
1
@AmirDora。我的GridViewItem类继承自RelativeLayout,而Cruceo的则继承自ImageView。正如我所写的,如果您的网格项有多个项目... - Jain

-10

请确保您的图像是正方形的。并且将容器设置为wrap_content。


9
对不起,顾客先生,您的图片需要为正方形。请下载照片编辑软件或应用程序,以便您将5000张图片编辑成正方形。 - busuu

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