Android网格视图:根据方向更改列数

16
我想要以以下方式以网格形式显示6张图片:
在纵向方向上,2列3行, 在横向方向上,3列2行。
通过使用Android GridView,并在layout-port和layout-land目录中定义不同的网格布局,我能够实现这种效果。
后来,根据我的活动要求,在manifest.xml中添加了一个参数。
android:configChanges = "mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale|screenSize"`

为了防止屏幕方向更改时重新创建我的活动。

添加此参数后,我的网格视图的表现不符合预期。有时它会显示1列,有时会显示2列,有时会显示3列。

我将 gridView.setNumberOfColumns(2)gridView.setNumberOfColumns(3) 方法放置在我的网格适配器的 get view 方法中,具体取决于设备的方向。

请帮助我在不删除 Manifest.xml 中的 android:configChanges 参数的情况下实现此效果。

9个回答

44

使用强大的资源系统。

在xml布局中,将列数设置为整数资源,然后在/values/integers.xml中将其设置为2,以适应竖屏模式,在/values-land/integers.xml中将其设置为3,以适应横屏模式

// 如果您在清单文件中进行了configChanges配置,则必须在onConfigurationChanged方法中从java代码中更改列数。


谢谢,现在是values-land和肖像模式下只有values,无论如何+1。 - Niklas
1
我认为为了更好地兼容各种设备,应该使用values-landvalues-port(而不是纯粹的values)。 - defhlt

12
@Override
public void onConfigurationChanged(Configuration newConfig) {
    grid.setNumColumns(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? 3 : 2);
    super.onConfigurationChanged(newConfig);
}

6

您可以使用编程方式设置列数

float scalefactor = getResources().getDisplayMetrics().density * 100;
int number = getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / (float) scalefactor);
gridView.setNumColumns(columns);

1
getDefaultDisplay().getWidth()现在已经过时了。有没有其他获取它的方法? - Ody

4

My solution:

values/dimens.xml:

<resources>
    <dimen name="grip_view_entry_size">160dp</dimen>
    <dimen name="grip_view_spacing">10dp</dimen>
</resources>

layout/gridview.xml

<GridView android:id="@+id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:numColumns="auto_fit"
    android:verticalSpacing="@dimen/grip_view_spacing"
    android:horizontalSpacing="@dimen/grip_view_spacing"
    android:stretchMode="columnWidth"
    android:gravity="center"
    android:scrollingCache="false"
    android:fastScrollEnabled="true"
    android:animationCache="false"/>

在你的片段中:
private void refreshGridView() {

    int gridViewEntrySize = getResources().getDimensionPixelSize(R.dimen.grip_view_entry_size);
    int gridViewSpacing = getResources().getDimensionPixelSize(R.dimen.grip_view_spacing);

    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();

    int numColumns = (display.getWidth() - gridViewSpacing) / (gridViewEntrySize + gridViewSpacing);

    gridView.setNumColumns(numColumns);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    refreshGridView();
}

@Override
public void onResume() {
    super.onResume();
    refreshGridView();
}

1
这个代码有效,应该被接受为正确答案。 - Jaky71

2
    @Override
    public void onConfigurationChanged(Configuration newConfig) {

        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            setContentView(R.layout.lay_vertical);
        } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            setContentView(R.layout.lay_horizontal);
        }

    };

根据您的需求再次加载gridview中的数据。

在清单文件中为该activity节点添加android:configChanges="orientation"。


你会得到一个异常,因为 setContentView 只能被调用一次。 - Jin35
我认为setcontentview不仅可以被调用一次,而且该特定布局中的所有内容都必须通过findViewById重新初始化,并且这将会很顺利。 - Amit Hooda

1
我根据屏幕尺寸而不是DPI来制作它。
public static int getGridColumnsCount(Context context){
    boolean landscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;

    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    float hi=displayMetrics.heightPixels/displayMetrics.xdpi;
    float wi=displayMetrics.widthPixels/displayMetrics.ydpi;
    float screenWidthInch  = landscape ? Math.max(wi, hi) : Math.min(wi, hi);
    float screenWidthCm = screenWidthInch * 2.54f;
    int columns = (int)(screenWidthCm/2);
    return columns < 3 ? 3 : columns;
}

1

如果您在清单文件中使用android:configChanges ="orientation",则您的活动在方向更改(从横屏到竖屏或反之亦然)时不会重新创建。如果您不想从清单文件中删除此标记,则必须重写onConfigchanged并在其中放置一些代码逻辑。


0

这是 XML:

<GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnCount="@integer/num_columns"
    android:rowCount="@integer/num_rows"
    android:orientation="vertical">
    <!-- TextViews, ImageViews, etc -->
</GridLayout>

然后在你的片段内部:

@BindView(R.id.gridLayout) GridLayout gridLayout;

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    final ArrayList<View> views = new ArrayList<>();
    for (int i = 0; i < gridLayout.getChildCount(); i++) {
        views.add(gridLayout.getChildAt(i));
    }
    gridLayout.removeAllViews();
    gridLayout.setColumnCount(getContext().getResources().getInteger(R.integer.num_columns));
    gridLayout.setRowCount(getContext().getResources().getInteger(R.integer.num_rows));
    for (int i = 0; i < views.size(); i++) {
        views.get(i).setLayoutParams(new GridLayout.LayoutParams());
        gridLayout.addView(views.get(i));
    }
}

0
将此代码添加到onCreate函数中。
 gridView_menu.setNumColumns(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? 3:4);

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