使GridView项目变为正方形


78

我希望我的物品GridView摆正。有两列,项目宽度为fill_parent(例如,它们占用尽可能多的水平空间。这些项目是自定义视图。

如何使物品的高度等于其可变宽度?

Answers:


107

扩展GridView列时,有一个更简单的解决方案。只需使用...覆盖GridView项布局的onMeasure ...

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

效果很好。我在答案中错过了几件事:1.高度被忽略,宽度作为高度传递。2.该方法应在项目和网格本身中被覆盖。
AlikElzin-kilaka

12
关于1:这就是方形的原因-“
mDroidd

2
@KarthikPalanivelu这将用于网格项目的布局,而不是GridView本身。您可以使用此代码段将RelativeLayout扩展到SquareRelativeLayout。
jdamcd

1
如果我在gridview中执行此操作,则将GridView变为正方形,而不是其子级。
丹尼尔·博

3
一个完整的答案将是不错的。您是说要扩展gridview?
StarWind0 2015年

56

或者,如果您想扩展View,只需执行一些非常简单的操作即可:

public class SquareImageView extends ImageView
{

    public SquareImageView(final Context context)
    {
        super(context);
    }

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

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


    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
    {
        final int width = getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh)
    {
        super.onSizeChanged(w, w, oldw, oldh);
    }
}

值得注意的super.onMeasure()是不需要。onMeasured要求是您必须致电setMeasuredDimension


2
像魅力一样工作..
谢谢克里斯

2
@ Chris.Jenkins我不同意您的最后评论:如果不致电super.onMeasure(),将不会在其中放置ImageView。因此,似乎它是onMeasure方法的第一行。
cyrilchampier 2015年

@nerith,这是在特定的设备上吗,因为我已经使用此代码很长时间了,从不陷入问题。有兴趣了解如何重现您所看到的内容。
克里斯·詹金斯(Chris.Jenkins),2015年

@ Chris.Jenkins不在特定设备上。我的SquareFrameLayout是从xml加载的。您是否通过编程方式添加了孩子?
cyrilchampier 2015年

哦,是的,这不适用于仅视图组视图。也许我应该提一下。
克里斯·詹金斯(Chris.Jenkins)

16

我不确定当前的小部件是否可行。最好的选择是将自定义视图放在自定义的“ SquareView”中。该视图只能包含1个子视图,并在调用其onLayout方法时强制其高度等于宽度。

我从未尝试过做类似的事情,但我认为应该不会太困难。另一种解决方案(也许稍微容易些)可能是对自定义视图的根布局进行子类化(例如,如果是LinearLayout,则创建SquareLinearLayout),然后将其用作容器。

编辑:这是一个似乎对我有用的基本实现:

package com.mantano.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class SquareView extends ViewGroup {

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

    @Override
    protected void onLayout(boolean changed, int l, int u, int r, int d) {
        getChildAt(0).layout(0, 0, r-l, d-u); // Layout with max size
    }

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

        View child = getChildAt(0);
        child.measure(widthMeasureSpec, widthMeasureSpec);
        int width = resolveSize(child.getMeasuredWidth(), widthMeasureSpec);
        child.measure(width, width); // 2nd pass with the correct size
        setMeasuredDimension(width, width);
    }
}

它被设计为有一个唯一的孩子,但是为了简单起见,我忽略了所有检查。基本思想是使用GridView设置的width / height参数测量子对象(在我的情况下,它使用numColumns = 4来计算宽度),然后对最终尺寸(高度=宽度)进行第二次遍历。 ..布局只是一个普通布局,它将唯一的子项布置在(0,0)处并具有所需的尺寸(左右,上下)。

这是用于GridView项的XML:

<?xml version="1.0" encoding="utf-8"?>
<com.mantano.widget.SquareView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="wrap_content">

    <LinearLayout android:id="@+id/item" android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:orientation="horizontal"
        android:gravity="center">

        <TextView android:id="@+id/text" android:layout_width="fill_parent"
            android:layout_height="wrap_content" android:text="Hello world" />
    </LinearLayout>
</com.mantano.widget.SquareView>

我在SquareView中使用了LinearLayout,以使其能够管理所有重力可能性,边距等。

我不确定此小部件对方向和尺寸变化的反应有多好(或不好),但似乎工作正常。


听起来不错,唯一的问题是正确编写onLayout(或onMeasure)。Currenlty我在ItemAdapter.getView()中设置了高度/宽度,但是我不喜欢这种解决方案。
anagaf 2011年

@anagaf我用刚刚测试过的代码编辑了答案,这似乎可行。这很容易理解,因此应该很容易解决,以防万一您发现一些小问题^^(不确定我是否应该编辑或发布第二个答案,对不起,如果我做错了!)
Gregory

1
上面的布局不起作用---我不知道为什么,但是子级存在一些细微的布局问题,这意味着,例如TextViews不会包装,而RelativeLayouts会变得非常混乱。但是,我确实在这里找到了一个等效项:stackoverflow.com/questions/2948212/…尽管我仍然需要进行一些调整(它的大小基于最大尺寸,而不只是宽度)。
大卫·

12

最终很容易使网格项变为正方形。

在网格适配器的“ GetView”方法中,只需执行以下操作:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    GridView grid = (GridView)parent;
    int size = grid.getRequestedColumnWidth();

    TextView text = new TextView(getContext());
    text.setLayoutParams(new GridView.LayoutParams(size, size));

    // Whatever else you need to set on your view

    return text;
}

这是唯一为我工作的解决方案...非常感谢!
Zeba 2014年

3
必须用“ getColumnWidth”替换“ getRequestedColumnWidth”,它对我有用..谢谢!
Ayad KaraKâhya17年

1
同样在这里:我不得不更换getRequestedColumnWidthgetColumnWidth和工作对我来说...谢谢!
Yahya

6

我不知道这是否是最好的方法,但是我完成了使自定义视图覆盖onSizeChanged的方法:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    if (getLayoutParams() != null && w != h) {
        getLayoutParams().height = w;
        setLayoutParams(getLayoutParams());
    }
}

我在LinearLayout和GridView中使用此自定义视图,并且两者都显示正方形!


哦,老兄,您是救生员,我已经为此奋斗了好几天。除非你有很多孩子,否则格雷戈里的答案很好。然后,正如一条评论所指出的那样,TextView不会包装,并且大多数视图不会重新调整其边界。但这解决了!
Makario

6

这对我有用!

如果您像我一样,并且因为minSdk小于16而不能使用getRequestedColumnWidth(),则建议您使用此选项。

  1. 在您的片段中:

    DisplayMetrics dm = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); int size = dm.widthPixels / nbColumns; CustomAdapter adapter = new CustomAdapter(list, size, getActivity());

  2. 在您的适配器中(在getView(int位置,View convertView,ViewGroup父级)中)

    v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, size));

  3. fragment.xml:

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

  4. custom_item.xml :(例如)

    <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/picture" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" />

希望它能对某人有所帮助!


5

如果您在xml中设置了固定的列数,则可以采用视图的宽度并将其除以列数。

如果您正在使用,auto_fit那么获取列数将有点棘手(没有getColumnCount()方法),但是这个问题应该可以以某种方式帮助您。

这是我在getView(...)具有固定列数的适配器方法中使用的代码:

    item_side = mFragment.holder.grid.getWidth() / N_COL;
    v.getLayoutParams().height = item_side;
    v.getLayoutParams().width = item_side;

5

尝试

<GridView
...
android:stretchMode="columnWidth" />

您也可以使用其他模式


4

这就是我在GridView中显示方形单元格的目的。我不确定您是否想要方形单元格或其他东西。

GridView grid = new GridView( this );
grid.setColumnWidth( UIScheme.cellSize );
grid.setVerticalSpacing( UIScheme.gap );
grid.setStretchMode( GridView.STRETCH_COLUMN_WIDTH );
grid.setNumColumns( GridView.AUTO_FIT );

然后,我要为每个单元格创建的视图必须对其执行以下操作:

cell.setLayoutParams( new GridView.LayoutParams(iconSize, iconSize) );

3

基于SteveBorkman的答案,即API 16+:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    GridView grid = (GridView)parent;
    int size = grid.getColumnWidth();

    if (convertView == null){
        convertView = LayoutInflater.from(context).inflate(R.layout.your_item, null);
        convertView.setLayoutParams(new GridView.LayoutParams(size, size));
    }

     //Modify your convertView here

     return convertView;
}

1

按照@Gregory的回答,我必须将图像包装在LinearLayout中,以防止GridView从正方形操纵其尺寸。请注意,应将外部LinearLayout设置为具有图像的尺寸,并且GridView列的宽度应为图像的宽度加上任何边距。例如:

    <!-- LinearLayout wrapper necessary to wrap image button in order to keep square;
    otherwise, the grid view distorts it into rectangle.

    also, margin top and right allows the indicator overlay to extend top and right.

    NB: grid width is set in filter_icon_page.xml, and must correspond to size + margin
    -->
<LinearLayout
        android:id="@+id/sport_icon_lay"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:orientation="vertical"

        android:layout_marginRight="6dp"
        android:layout_marginTop="6dp"
        >

    <ImageButton
            android:id="@+id/sport_icon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:maxHeight="60dp"
            android:maxWidth="60dp"
            android:scaleType="fitCenter"
            />
</LinearLayout>

和GridView一样:

   <GridView
        android:id="@+id/grid"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fillViewport="true"

        android:columnWidth="66dp"

        android:numColumns="auto_fit"
        android:verticalSpacing="25dp"
        android:horizontalSpacing="24dp"
        android:stretchMode="spacingWidth"

        />

-1

在您的活动中

 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 valX = displaymetrics.widthPixels/columns_number;

在GridView的CustomAdapter中

 v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, YourActivity.valX));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.