Android

[Android] GridView の横幅を wrap_content に従わせる

GridView の中のアイテムを整列させるルールとして stretchMode を指定するのですが、アイテム同士が隙間なく並んだ状態で GridView 全体を画面中央に寄せるという要望は、既存の GridView では思ったように実装出来ませんでした。

以下の実装をしました。

  • GridView に strechMode="none"
  • GridView の横幅に wrap_cotent"
  • GridView の親ビューに gravity="center"
  • GridView の親ビュー横幅に match_parent

ですが、何故か GridView には wrap_content が効かずに、match_parent のような振る舞いになってしまう。

どうやら自身の縦幅・横幅を決定する onMeasure() で、計算するしかないみたいです。その実装をメモしておきます。

GridView の横幅を onMeasure() で計算する

FixedGridView という GridView のサブクラスを作り、onMeasure() で、横幅と縦幅を計算しています。

計算結果を setMeasuredDimension() にセットすれば OK です。

カラムサイズを決め打ちしていますが、API Level 16 以上では、getColumnWidth() が使えます:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.GridView;

public class FixedGridView extends GridView {

  private static final int COLUMN_SIZE = 150;

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

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

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

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

    int num = getNumColumns();
    float density = getResources().getDisplayMetrics().density;
    int px = Math.round(COLUMN_SIZE * density);

    int width  = px * num; // px * カラム数
    int height = px * (int)Math.ceil((float)getAdapter().getCount()/(float)num); // px * 行数
    setMeasuredDimension(width, height);
  }
}

後は、アイテム同士が隙間なく並んだ状態で GridView 全体を画面中央に寄せるレイアウトを記述すれば OK です:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:padding="6dp"
  android:gravity="center">

  <FixedGridView
    android:id="@+id/gridview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnWidth="150dp"
    android:numColumns="auto_fit"
    android:stretchMode="none"/>

</LinearLayout>

参考