カテゴリー
Kotlin言語

ゼロから始めるAndroidアプリ(Kotlin編)Unit2 – 2 第4回:RecyclerView(画像の表示)

Android Developers > スタートガイド > Kotlin と Android をゼロから学ぶ > Unit2 – レイアウトUnit2-2 第4回 の内容をまとめたものです(翻訳ではありません)


Unit2 – 2 第4回

第4回の内容は以下の通りです

  • 前回作成したアプリ(Affirmationsアプリ)を改良します
  • RecyclerView でテキストと画像をリストで表示します
  • Card と呼ばれるUI部品を使います
    • Material の Android ライブラリに用意されている MaterialCardView という Card(ウィジェット)を使います
  • テーマで設定されている色を変更して見栄えを変えてみます

具体的にはつぎのようなレッスンです

  • RecyclerView に画像を追加する方法
  • RecyclerView のアイテム(ビューホルダー)のレイアウトにMaterialCardView を使う方法
  • テーマ色やアプリアイコンを変更する方法

注意:このチュートリアルを Android Studio 4.0 以前を使って進める場合には設定が必要です

  • このチュートリアルでは Materialコンポーネントやテーマファイル(themes.xml)を使用します
  • バージョン 4.0 以前の Android Studio でこれらを利用するには自分で Android Studio に設定をする必要があります
  • 具体的な設定方法については Unit2 – 1 第6回 またはこちらを参考にしてください
  • Android Studio 4.1 以降であれば面倒な設定は必要ありません。できるだけバージョン4.1以降の Android Studio を使うことをおすすめします

アイテム(ビューホルダー)に画像を追加する

前回(Unit2 – 2 第3回)作成したアプリのプロジェクトを開いておいてくださいね

  • リストのアイテム(ビューホルダー)のレイアウトを修正して、テキストと一緒に画像を表示するようにアダプタを書き換えます
  • 画像は こちら からダウンロードしたものを使います
  • 画像は表示するテキストメッセージに合わせて10個、名前は image1.jpg ~ image10.jpg です

画像をプロジェクトに読み込む

画像はリソースとして読み込んでから使うんですね

  • Android Studio を起動してプロジェクトにダウンロードした画像を読み込みます
    1. ウィンドウ左タブのResource Manager > +アイコン > Import Drawables
    2. PC上にあるダウンロード画像を選択して読み込む
    3. Next > Import
    4. app/src/main/res/drawable に読み込まれる
  • プロジェクトへ読み込んだ画像はリソースIDで参照できます
  • Kotlinコードからは R.drawable.image1 のようにして参照できます

Affirmation オブジェクトに画像を追加する

データはオブジェクト化して使います

  • データクラス Affirmation に画像のリソースIDを保持しておくためのプロパティを追加します
  • Affirmation オブジェクトひとつで、テキストのリソースIDと画像のリソースIDを両方保持できます

Affirmation.kt を修正する

  • model パッケージにある Affirmation.kt を開きます
  • Affirmation クラスのコンストラクタを修正します(int 型の imageResourceId 変数を追加します)
  • 次のように書き換えます
package com.example.affirmations.model

data class Affirmation(
   val stringResourceId: Int,
   val imageResourceId: Int
)

アノテーション(注釈)を使う

@で始まってる謎の文字列ですね

  • Affirmation クラスでは stringResourceId と imageResourceId はどちらも整数です
  • 同じ型なので、呼び出すときに誤って imageResourceId が先だと勘違いしたままコードを書いてしまうかもしれません
  • これを避けるためには、リソースアノテーション(Resource annotation)を使います
  • アノテーションはクラス、メソッド、パラメータに追加情報としてつけられます
  • アノテーションには必ず @ がつきます
  • 文字列のリソースIDのほうに @StringRes、画像のリソースIDの方に @DrawableRes を付けます
  • こうしておくことで、間違ったタイプのリソースIDが指定されたときに警告が出るようになります

Affirmation.kt にアノテーションを付ける

  1. stringResourceId に @StringRes をつける
  2. imageResourceId に @DrawableRes をつける
  3. androidx.annotation.DrawableRes と androidx.annotation.StringRes を import します(場所はファイルの先頭にあるパッケージ宣言のあとです)
  4. こんなかんじになります
package com.example.affirmations.model

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes

data class Affirmation(
   @StringRes val stringResourceId: Int,
   @DrawableRes val imageResourceId: Int
)

データソース(Datasourceクラス)を修正します

最後にリスト化すればデータソースが完成

  • データオブジェクト(Affirmationクラス)のコンストラクタを変更したので、それにあわせてデータソース(Datasourceクラス)を修正します
  • Affirmation オブジェクトを初期化するところに画像のリソースIDを追加します

Datasource.kt を修正する

  1. Datasource.kt を開きます
  2. Affirmation インスタンスを生成するところにエラーがでていると思います
  3. Affirmation のコンストラクタに画像のリソースIDを指定します。リソースIDはKotlinコードでは R.drawable.image1 のようにして参照できます
  4. こんな感じになります
package com.example.affirmations.data

import com.example.affirmations.R
import com.example.affirmations.model.Affirmation

class Datasource() {

    fun loadAffirmations(): List<Affirmation> {
        return listOf<Affirmation>(
            Affirmation(R.string.affirmation1, R.drawable.image1),
            Affirmation(R.string.affirmation2, R.drawable.image2),
            Affirmation(R.string.affirmation3, R.drawable.image3),
            Affirmation(R.string.affirmation4, R.drawable.image4),
            Affirmation(R.string.affirmation5, R.drawable.image5),
            Affirmation(R.string.affirmation6, R.drawable.image6),
            Affirmation(R.string.affirmation7, R.drawable.image7),
            Affirmation(R.string.affirmation8, R.drawable.image8),
            Affirmation(R.string.affirmation9, R.drawable.image9),
            Affirmation(R.string.affirmation10, R.drawable.image10)
        )
    }
}

アイテム(ビューホルダー)のレイアウトに ImageView を追加する

表示する場所を作るんですね

  • リストのアイテム(ビューホルダー)のレイアウトは list_item.xml です
  • list_item.xml に ImageView を追加して画僧を表示します
  • 2つのUI部品が縦に配置されるように LinearLayout を使います

LinearLayout はすべての 子View を縦(vertical)または横(horizontal)、いずれか一方向に並べます

LinearLayout を追加する

  1. list_item.xml を開きます(res > layout > list_item.xml
  2. すでに記述してある TextView を囲むように LinearLayout を配置します。orientation 属性には vertical を指定します
  3. TextView のところにあった xmlns の部分(スキーマ)は、LinearLayout のほうに移動します(エラーが消えます)
  4. 次のようになります
<?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:orientation="vertical">

    <TextView
        android:id="@+id/item_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

ImageView を追加する

  • TextView の上に ImageView を追加します。リソースID は item_image とします
  • list_item.xml はこんな感じになります
<?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:orientation="vertical">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="194dp"
        android:id="@+id/item_image"
        android:importantForAccessibility="no"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/item_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
  • ImageView の幅を match_parent に、高さを 194dp に設定しています。表示するデバイスのスクリーンサイズに合わせて、いつでもいくつかのアイテム(ビューホルダー)が表示されるようになります
  • scaleType は centerCrop にします
  • 表示されるのは単なるイメージ画像ですので importantForAccessibility 属性は no にします

画像を表示するようにアダプタ(ItemAdapterクラス)を修正します

アダプタが表示を管理しているの

アダプタ(ItemAdapter クラス)を修正して、ビューホルダーに画像が設定されるようにします

ItemViewHolder の修正

表示に合わせたビューホルダーに変更

  1. ItemAdapter.kt を開きます(app > java > adapter > ItemAdapter
  2. ItemViewHolder クラスに ImageView を参照するためのプロパティを追加します
  3. 次のようになります
class ItemViewHolder(private val view: View): RecyclerView.ViewHolder(view) {
    val textView: TextView = view.findViewById(R.id.item_title)
    val imageView: ImageView = view.findViewById(R.id.item_image)
}

onBindViewHolder() メソッドの修正

UI部品とデータを結び付けます

  1. onBindViewHolder() メソッドのところに移動します
  2. アイテム(ビューホルダー)の ImageView(UI部品)に画像のリソースIDを設定します
  3. 次のようになります
    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textView.text = context.resources.getString(item.stringResourceId)
        holder.imageView.setImageResource(item.imageResourceId)
    }

アプリを実行してみます

画像がリストで表示されたら大成功

  • アプリをビルドして実行してみます
  • 画像とテキストメッセージが並ぶリストが表示されれば成功です

UIの仕上げをする

かっこいいアプリにしたいです

  • ちょっとした修正を加えてUIの見栄えをよくしてみます
  • KotlinコードやレイアウトのXMLを調整するだけでアプリの見栄えが一層よくなります

レイアウトの属性を設定する方法

レイアウトの属性を設定する方法は2通りあります。どちらで設定しても構いません

  • 方法1:Code表示にしてXMLファイルを直接書き換えます
  • 方法2:Design表示にしてから右側の Attributes パネルで書き換えます

余白を入れる

うん、配置に余裕があるときれいかも

画面に表示されるUI部品(View)のまわりに余白を作ります

  1. list_item.xml を開きます(app > res > layout > item_list.xml
  2. LinearLayout の padding を 16dp に設定します
  3. TextView の padding も 16dp に設定します
  4. TextView にはさらに textAppearance 属性を使ってテキストのスタイルを設定します
  5. textAppearrance に設定できるスタイルはあらかじめ用意されているものがあります。こちら blogpost on Common Theme Attributes を参照してください
  6. item_list.xml は次のようになります
<?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:orientation="vertical"
    android:padding="16dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="194dp"
        android:id="@+id/item_image"
        android:importantForAccessibility="no"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/item_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:textAppearance="?attr/textAppearanceHeadline6" />

</LinearLayout>

アプリを実行して、UI画面が変化したことを確認しておきます

レイアウトに Card を使う

項目のレイアウトをまるごと Card に入れちゃえばいいの

  • アイテム(ビューホルダー)同士の間の区切りがはっきりしないので、テキストが画像の上に表示されているのか、下に表示されているのかが分かりにくくなっています
  • UI部品の Card(View)を使ってこれを改善してみます
  • Card を使えば、UI部品をまとめて統一感のあるデザインに簡単に仕上げられます
  • 今回は MaterialCardView というカードを使います
  • Card についての詳しい説明は guide on cards をどうぞ

MaterialCardView の設定手順

  1. list_item.xml を開きます
  2. LinearLayout を囲むように MaterialCardView を設定します
  3. LinearLayout にある xmlns の部分(スキーマ)を MaterialCardView に移動します
  4. MaterialCardView の設定をします
    • layout_width を match_parent にします
    • layout_height を wrap_content にします
    • layout_margin を 8dp にします
  5. LinearLayout にあった padding の設定を削除します(Card を使うので余白を設定する必要はありません)
  6. コードは次のようになります
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp">

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

        <ImageView
            android:id="@+id/item_image"
            android:layout_width="match_parent"
            android:layout_height="194dp"
            android:importantForAccessibility="no"
            android:scaleType="centerCrop" />

        <TextView
            android:id="@+id/item_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:textAppearance="?attr/textAppearanceHeadline6" />

    </LinearLayout>

</com.google.android.material.card.MaterialCardView>

アプリを実行して、アイテム(項目)がそれぞれ枠に囲まれて見やすくなったことを確認しておきます

アプリのテーマ色を変更する

前にも出てきましたよね、COLOR TOOL

  • デフォルトのアプリのテーマ色を変更してみます
  • アプリのテーマ色をやわらかめの青に変えてみます
  • Material Design の COLOR TOOL に用意されている色合いからアプリに使いたい青を探します
  • ここでは、この3色を使います
    • blue_200: #FF90CAF9
    • blue_500: #FF2196F3
    • blue_700: #FF1976D2

colors.xml に色を追加する

データをあちこちに書き込んじゃうと、あとから修正するのが大変なの

アプリで使用する色は colors.xml に登録します。色のリソース(カラーリソース)が一元化されて分かりやすくなります

  1. colors.xml を開きます(res > color > colors.xml
  2. 以下のように設定を追加します
<color name="blue_200">#FF90CAF9</color>
<color name="blue_500">#FF2196F3</color>
<color name="blue_700">#FF1976D2</color>

テーマ色を変更します

colors.xml にカラーリソースとして登録した色を、テーマ色として設定してみます

  1. themes.xml を開きます(res > values > themes > themes.xml
  2. <!– Primary brand color. –> のところにある colorPrimary 属性を @color/blue_500 に変更します
  3. colorPrimaryVariant 属性を @color/blue_700 に変更します
  4. こんな風に書き換えます
<item name="colorPrimary">@color/blue_500</item>
<item name="colorPrimaryVariant">@color/blue_700</item>

アプリを実行して、アプリのバーの色が変化したことを確認しておきます

ダークテーマのテーマ色を変更します

設定方法は通常のテーマを書き換えるのと同じです

  1. ダークテーマ用の themes.xml を開きます(res > values > themes > themes.xml (night)
  2. こんな風に書き換えます
<item name="colorPrimary">@color/blue_200</item>
<item name="colorPrimaryVariant">@color/blue_500</item>
  • アプリをビルドしてダークテーマにして実行してみます
  • ダークテーマでの実行方法は Unit2 – 1 第6回 にまとめてあります

この段階で、colors.xml に登録されていても使ってない色があれば削除しちゃって構いません(たとえばデフォルトで使っている purple など)


  • アプリをダークテーマで実行したとき、ダークテーマの colorPrimary に設定した色がアプリ上部のバーに適用されません。これは仕様でバグではありません
  • ダークテーマではアプリのバーやその他の比較的面積の広い部分には colorPrimary でなく、暗めの背景(colorSurface)が使われます
  • Material によって、ダークテーマのときは面積の広い部分にできるだけ明るい色を使わないように示されているためです
  • ボタンやほかの小さなアクセント的な部分については colorPrimary で設定された色で表示されます

アプリのランチャーアイコンを変更する

アイコンってアプリの顔って感じかも

ランチャーアイコンの変更手順

  1. Image Asset Studio を起ち上げます(drawable フォルダを右クリック > New > Image Asset)
  2. Foreground , Background にそれぞれダウンロードしたアイコンのXMLファイルを指定して Next をクリックします
  3. 上書きの確認ダイアログが出るので Finish をクリックします
  4. 必要に応じて不要になったアイコンやフォルダを削除します
    • Delete で Safe delete (with usage search) を選択すると、ファイルやフォルダが使用中でないか確認できます
  5. 詳しくは Unit2 – 1 第7回 をどうぞ

最後に

  • コードを整理して、見やすくしておきます
  • 以上で Affirmations アプリの改良版は完成です
  • このアプリのプロジェクトはこちらからダウンロードできます

まとめ

RecyclerView 長かったですね、おつかれさました

  • RecyclerView に表示する情報を追加したいときは、元になるオブジェクト化したデータ(データモデルクラス)と、それらをまとめたデータソースを修正します
  • さらにアイテム(ビューホルダー)のレイアウト、UI部品にデータを設定するためのアダプタを更新します
  • クラスのコンストラクタに正しいリソースIDが渡されるように、リソースアノテーションを使います
  • Android向けのMaterialコンポーネントを使えば、Materialデザインのガイドラインに沿ったアプリが簡単に作成できます
  • MaterialCardView は Material で提供される Card(UI部品)です
  • 色や余白をちょっと調整するだけで、アプリの見栄えはずっとよくなります

参考