GridViewによるサムネイル表示 – その2

前回記事で、GridViewのサムネイルが画面に収まらない問題が発生。そこで、スクロールバーを付けて、

  • 「日付」「カテゴリ(とサブカテゴリ)」はスクロールされずに固定で画面上部に表示される
  • 表示内容が多いとき「コメント」と「サムネイル」はスクロールされる

みたいな感じにしたいと考え、コメントとサムネイルをScrollViewで囲めばいいんじゃん?と安易に考えていた。が、その方法だとScrollviewの内側にある筈のTextViewが無視され、GridViewがサムネイル1行分の高さだけ表示され、低い高さのGridViewにスクロールバーが表示されるという謎な結果になって呆然…

当初は楽勝と思ったのだが、これにはなかなか深い問題が関わっており、意外と面倒だった。

スポンサーリンク

GridViewクラスのオーバーライド

GridViewやListViewは確保された領域に全体が収まらない時に自身のViewの中に自動でスクロールバーが表示される仕様。そもそも、その手のViewに対してScrollViewを外側に配置するのは推奨されていないらしい。

なんとかGridViewの改造をせずに済む方法は無いものかと探したが、どうやら他に方法が無くそれ以外だとGridViewを1から作り直す位しかないようで、結局こちらの記事を見つけ、GridViewの拡張クラスを定義する方法を取った。

要はOnMeasureメソッドで高さを計測する時に、常にGridViewに表示するべき内容の高さを返すことがポイントのようだ。

親クラスはGridViewであり、基本動作に何も手を加えていないので、javaコード上はクラス変数の型宣言を変えるだけでコードの変更は特に必要ない。

ExpandableHeightGridView.java

package com.example.photologger;

import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.GridView;
import android.content.Context;

public class ExpandableHeightGridView extends GridView {

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

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

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

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);

        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

画面のレイアウトXML

前回記事で作成したレイアウトをベースに、上記のGridView改造クラスExpandableHeightGridViewとScrollViewを追加する。

上記ExpandableHeightGridViewクラスを使う場合は、単にクラス名を書くのでは駄目でcom.example.photologger.ExpandableHeightGridViewとモジュールを明示する必要がある。

日付とカテゴリのテキストの下の残りの高さをScrollViewに割り当てるのにLinearLayoutの時のようにlayout_height=”fill_parent”と指定しても期待通りにならず悩む。色々調べた結果ConstrainedLayoutではlayout_heightに0を指定すればよいと分かり解決。

activity_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DetailActivity">

  <TextView
      android:id="@+id/date"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="3dp"
      android:layout_marginTop="3dp"
      android:padding="3dp"
      android:textSize="24sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

  <TextView
      android:id="@+id/category"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="3dp"
      android:layout_marginEnd="3dp"
      android:textColor="#2020ff"
      android:textSize="20sp"
      android:padding="3dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/date" />

  <ScrollView
      android:layout_width="0dp"
      android:layout_height="0dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"      
      app:layout_constraintTop_toBottomOf="@+id/category">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

      <TextView
          android:id="@+id/comment"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:padding="3dp" />

      <com.example.photologger.ExpandableHeightGridView
          android:id="@+id/tn_grid"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:columnWidth="100dp"
          android:gravity="center"
          android:isScrollContainer="false"
          android:numColumns="auto_fit"
          android:stretchMode="spacingWidthUniform" />

    </LinearLayout>

  </ScrollView>

</android.support.constraint.ConstraintLayout>

実行結果

実行結果は以下。まずは、スクロールする前の状態。

そして、下向きにスワイプして下までスクロールすると…

期待通り日付やカテゴリは固定表示され、コメントとサムネイルだけがスクロールされた。GridViewの改造クラスが必要になるとは予想外だったが、なんとか目標通りの画面にすることが出来た。

コメント