View on GitHub
mixi-inc/AndroidTraining
アプリのリソース管理
この章では、Android アプリ内で利用する、静的リソースに関する扱い方を学びます。

参考:App Resources | Android Developers

目次

アプリのリソース管理の基本

Android では、Java のコードと分離した形で静的リソースを管理する仕組みを備えています。
Android プロジェクトの中にある、resディレクトリがこの仕組みを利用する上で重要なディレクトリです。
AndroidStudioのプロジェクトでは、resディレクトリは src/main/resがデフォルトになっています。

Java のプログラムから、resディレクトリに配置した静的リソースへのアクセスは、自動で生成されるRオブジェクトを介して行います。

Android で扱うことの出来るリソース

Android では、以下のリソースを静的リソースとして扱うことができます。

  1. String Resource
    • 定型文など
  2. Drawable Resource
    • ビットマップ、ベクタ画像など
  3. Style Resource
    • UI スタイル、テーマ
  4. Menu Resource
    • メニュー項目
  5. Color State List Resource
    • 状態に対応した色の管理
  6. Value Resource
    • 各種プリミティブ値
  7. Animation Resource
    • アニメーション
  8. Raw Resource
    • 音声・動画・画像などの生データ
  9. Layout Resource
    • 画面レイアウト
  10. XML Resource
    • 任意の XML ファイル

これらの静的リソースは、読み取り専用です。改変を加えて保存することはできません。

静的リソースの配置場所

Project Composition

静的リソースはすべて、プロジェクトディレクトリ内にあるresディレクトリ以下に配置されます。

リソースの種類に応じて、res以下にも様々なディレクトリが用意されています。
resディレクトリ直下に直接ファイルを配置するとコンパイルエラーとなりますので、適切なディレクトリのなかに配置してください。

下記の表に、リソースの種類とディレクトリ構造の対応を示します。

ディレクトリ名 扱うリソース
res/animator Animation Resource(Property Animation)
res/anim Animation Resource(Tween Animation)
res/color Color State List Resource
res/drawable Drawable Resource
res/layout Layout Resource
res/menu Menu Resource
res/raw Raw Resource
res/values Value Resource, String Resource, Style Resource
res/xml 任意の XML ファイルリソース。Google Analytics の設定ファイルなど

リソースディレクトリの命名規則

各種リソースディレクトリには、命名規則がさだめられています。

<resources_name>-<configuration_qualifier>

<resources_name>は、静的リソースの種類を示します(上述の表のとおりです)。 <configuration_qualifier>は、様々なデバイスの状態に応じてリソースを自動で使い分けることを明示するものです。
複数の状態を宣言する場合は、-で結合していきます。

// hdpi 端末向けの Drawable Resource
SampleProject/res/drawable-hdpi

// 英語ロケール向けの Value Resource
SampleProject/res/values-en

// hdpi 端末向けの、横画面用 Drawable Resource
SampleProject/res/drawable-land-hdpi

リソースへのアクセス

Resource ID

各リソースには、リソースを一意に識別するための ID が割当てられます。

リソースの種類によって、XML の属性(android:idまたはandroid:name)で ID を割当てるものと、ファイル名を ID とするものがあります。

この ID は、Android SDK に含まれているaaptという仕組みで自動的に生成されるものです。aaptは、リソースディレクトリに含まれる各種リソースをコンパイル・最適化し、リソースの ID を生成します。
リソースファイルに何らかの問題がある場合、aaptがコンパイルエラーとして扱うため、リソースの ID が生成できなくなることに注意してください。

Java

aaptは、リソースファイルをコンパイルするとR.javaというプログラムを自動生成します。
このRクラスには、各種リソースの ID が詰め込まれています。
リソース毎に Facade パターンで分類されたクラスがあり、その下にリソース ID を扱う int 型定数値が含まれます。

Rクラスのパッケージは、アプリのパッケージに対応しています。jp.mixi.sampleパッケージでアプリを作成していた場合は、jp.mixi.sampleパッケージの直下にRクラスが生成されます。

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */
package jp.mixi.sample;

public final class R {
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
}

よって、以下の様な文法が成立します。

[{package_name}.]R.{resource_type}.{resource_id}

{package_name}は任意で記述します。

Android フレームワーク自身も、Rクラスを持っています。
Android フレームワークが持っているRクラスには、標準で用意されている各種リソースの ID が含まれていますので、Android 標準のリソースを利用したい場合に有用です。
ただし、Android フレームワークが持っているRクラスは直接 import しないようにします。代わりに、FQDN でアクセスするようにします。

// NG
import android.R;

public class HogeActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // android.R クラスの参照。NG な例。
        R.id.text_1;
    }
}
public class HogeActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // android.R クラスの参照。OK。
        android.R.id.text_1;
    }
}

XML

静的リソースへは、XML からも参照することができます。 XML で静的リソースへアクセスする場合も、R オブジェクトに生成される ID と同じものを利用します。

XML からの参照の記述は以下の文法に従います。

@[{package_name}:]{resource_type}/{resource_id}

Rクラスと同じく、{package_name}は任意で記述します。

XML 上で Android フレームワークのリソース ID を参照する場合は、以下のように記述します。

@android:id/text_1

リソース ID の参照方法の対応表

Java、XML それぞれのリソース ID の参照方法は以下のとおりです。

リソースの種類 Java からの ID の参照 XML からの ID の参照 ID を決める要素
String Resource R.string.hogehoge @string/hogehoge 各 String Resource のandroid:name属性
String Resource(Plurals) R.plurals.hogehoge @plurals/hogehoge 各 String Plurals Resource のandroid:name属性
String Resource(Array) R.array.hogehoge @array/hogehoge 各 String Array Resource のandroid:name属性
Drawable Resource R.drawable.hogehoge @drawable/hogehoge ファイル名
Style Resource R.style.hogehoge @style/hogehoge 各 Style Resource のandroid:name属性
Menu Resource R.menu.hogehoge @menu/hogehoge ファイル名
Color State List Resource R.color.hogehoge @color/hogehoge ファイル名
Value Resource(Integer) R.integer.hogehoge @integer/hogehoge 各 Value Resource のandroid:name属性
Value Resource(Integer Array) R.array.hogehoge @array/hogehoge 各 Value Resource のandroid:name属性
Value Resource(Typed Array) R.array.hogehoge @array/hogehoge 各 Value Resource のandroid:name属性
Value Resource(Boolean) R.bool.hogehoge @bool/hogehoge 各 Value Resource のandroid:name属性
Value Resource(Dimension) R.dimen.hogehoge @dimen/hogehoge 各 Value Resource のandroid:name属性
Value Resource(Color) R.color.hogehoge @color/hogehoge 各 Value Resource のandroid:name属性
Value Resource(ID) R.id.hogehoge @id/hogehoge 各 Value Resource のandroid:name属性
Layout Resource R.layout.hogehoge @layout/hogehoge ファイル名
XML Resource R.xml.hogehoge @xml/hogehoge ファイル名
Animation Resource(Tween Animation) R.anim.hogehoge @anim/hogehoge ファイル名
Animation Resource(Property Animation) R.animator.hogehoge @animator/hogehoge ファイル名
Raw Resource R.raw.hogehoge - ファイル名

String Resource

文字列リソースです。UI で使用する定型文など、ユーザに見えるものはこのリソースとして扱うことが推奨されています。

プロジェクト作成後には、デフォルトでstrings.xmlというファイルが作られていますが、任意のファイル名で保存することも可能です。

文字列リソースの中にも、いくつか種類があり、単なる定型文の宣言だけでなく、文字列フォーマットを提供したり、配列として管理したり、複数形の表現を宣言したりすることも出来るようになっています。

定型文

最も一般的な、定型文の定義方法です。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello_world">Hello World</string>
    <string name="hoge">Hoge</string>
</resources>

Activity や Fragment など、Context を持っている所では、以下のように文字列を取り出します。

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // String 型の変数 hello に、xml で定義した Hello World が代入される
        String hello = getString(R.string.hello_world);
    }
}

String Array

文字列を配列として定義します。 ひとまとまりの配列で1つのリソースとして扱いたい場合に便利です。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="foo_bar">
        <item>Foo</item>
        <item>Bar</item>
    </string-array>
</resources>

Activity や Fragment など、Context を持っている所では、以下のように文字列を取り出します。

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Resources オブジェクトを介して取得するようにする
        String[] array = getResources().getStringArray(R.array.foo_bar);
    }
}

Format

プレースホルダを用いることで、可変な文字列をリソースとして提供することができます。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="my_format">私は、%1$d個のりんごを持っています。</string>
    <string name="my_format_2">私は、%1$d個のりんごと、%2$d個のにんじんを持っています。</string>
</resources>

プレースホルダに用いられる%1や%2の数字は、後述する参照方法で渡す引数の順番と一致させます。

Activity や Fragment など、Context を持っている所では、以下のように文字列を取り出します。

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // フォーマット用に、可変長引数を受け入れるメソッドがあるので、こちらを利用する
        // "私は、1個のりんごと、2個のにんじんを持っています。"
        String formatted = getString(R.string.my_format_2, 1, 2);
    }
}

Plurals

複数形の表現もリソースとして宣言できます。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <plurals name="my_eggs">
        <item quantity="one">I have one egg.</item>
        <item quantity="other">I have %d eggs.</item>
    </plurals>
</resources>

<item>要素のquantity属性には、zeroonetwofewmanyotherの中から設定出来ます。それぞれの言語の文法的特性によって、どのquantity属性を設定出来るか決まっています。

Activity や Fragment など、Context を持っている所では、以下のように文字列を取り出します。

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // フォーマットも定義する場合は、複数形のquantityを第2引数に渡し、フォーマットに当てはめる変数を第3引数以降に指定する
        // "I have 2 eggs."
        String quantity = getResources().getQuantityString(R.plurals.my_eggs, 2, 2);
    }
}

Drawable Resource

グラフィックリソースです。png/jpeg/gif 画像や、9 patch 形式の画像の他、XML で定義した図形などもこのリソースとして扱われます。
アニメーションgifには対応していません。
png 画像の利用が推奨されており、jpeg 画像は「容認されている」扱いとなっています。gif 画像は非推奨です。

後述するディレクトリ階層によって、解像度ごとに異なるグラフィックリソースを提供することが可能です。
ただし、解像度ごとのディレクトリ階層で分けていない場合、あるいは該当する解像度のリソースディレクトリがない場合は、システムによって適宜拡大・縮小が行われます(端末の解像度に依って、画像が荒くなる場合が発生し得ることを意味する)。

また、アプリのビルドプロセスの中で、画像リソースは最適化が行われます。
これによって、不必要にメモリを消費することを抑制することができます。もし最適化を行わせたくない場合は、Drawable Resource ではなく、Raw Resource として扱うようにします。

Drawable にはいくつかの種類がありますが、Activity や Fragment など、Context を持っている所では、Drawable の種類にかかわらず、以下のように Drawable を取り出します。

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Drawable オブジェクトの取得
        Drawable drawable = getResources().getDrawable(R.drawable.hogehoge);
    }
}

Drawable の種類に応じたサブクラスがあるので、適宜キャストして使います。

Bitmap Drawable

png や jpg、gif 形式の画像リソースです。

9-patch Drawable

9-patch と呼ばれるフォーマットに従った png 画像リソースです。
ストレッチ可能な領域を指定することで、画像を割当てる View のサイズによって、画像リソースの拡縮による劣化なしに扱う事ができるようになります。

詳しくは、Draw 9-patch | Android Developersを御覧ください。

Layer List Drawable

複数の Drawable 要素をレイヤ上に並べた XML のグラフィックリソースです。 <item>要素を用いて、Drawable への参照を記述したり、後述する各種 Drawable を子要素に持つレイヤを作ったりすることもできます。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 一番下のレイヤに配置する、グレーで塗りつぶされた四角形の Drawable を持つ item 要素 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- 一番上のレイヤに配置する、薄茶色で塗りつぶされた四角形の Drawable を持つ item 要素 -->
    <!-- 上端から 30dp 分のオフセットが設定されている -->
    <item android:top="30dp">
        <shape android:shape="rectangle">
            <solid android:color="#deb887"/>
        </shape>
    </item>
</layer-list>

Sample Layer List Drawable

State List Drawable

UI の状態に応じた Drawable 要素を管理するグラフィックリソースです。 XML で、状態に対応する Drawable への参照を宣言します。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- View が押された状態の Drawable -->
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
    <!-- View が通常の状態の Drawable -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
</selector>
View の状態が何もない時View が押された状態
Sample State List Drawable for Unpressed Sample State List Drawable for Pressed

Level List Drawable

一定の規定値に依って Drawable 要素を管理するグラフィックリソースです。 XML で、規定値に対応する Drawable への参照を宣言します。

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Level が 最高 0 までの時の Drawable への参照 -->
    <item android:maxLevel="0" >
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- Level が 最高 1 までの時の Drawable への参照 -->
    <item android:maxLevel="1" >
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
</level-list>

Levelの設定はプログラムから行うことができます。

View view = findViewById(R.id.my_view);
Drawable levelListDrawable = view.getBackground();
levelListDrawable.setLevel(0); // level を 0 に設定 -> 薄いグレーに
// ...
levelListDrawable.setLevel(1); // level を 1 に設定 -> 濃いグレーに
Level = 0Level = 1
Level 0 Drawable Level 1 Drawable

Transition Drawable

複数の Drawable のクロスフェードを管理する XML グラフィックリソースです。

下記の例では、薄いグレーから濃いグレーへのクロスフェードをするような Drawable の宣言となります。

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 最初の状態 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- 次の状態 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
</transition>

このままではクロスフェードが実行されません。 実行するには、Java のコードで、クロスフェードの実行時間を与えて実行するようにします。

View transitionView = findViewById(R.id.TransitionView);
TransitionDrawable transition = (TransitionDrawable) transitionView.getBackground();
// 5秒間クロスフェードを実行する
transition.startTransition(5000);
最初途中最後
Before Transition Starts Transition On Going After Transition Ends

Inset Drawable

Drawable の中に別の Drawable を差し込む XML グラフィックリソースです。 View が、View 自身より小さい背景グラフィックを要求する場合に便利です。 また、単純に Drawable に対してマージンをつけることにも利用できます。

<?xml version="1.0" encoding="utf-8"?>
<!-- 上端と左端に 10dp ずつ余白が設定される -->
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:insetTop="10dp"
    android:insetLeft="10dp"/>

Inset Drawable

Clip Drawable

Drawable のレベルによって、別の Drawable を切り抜く XML のグラフィックリソースです。

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:clipOrientation="horizontal"
    android:gravity="right"/>

初期状態では、全ての領域が切り抜かれた状態になります(Level = 0)。 この状態を制御するには、Java のコードから ClipDrawable オブジェクトに対して setLevel() を呼び出す必要があります。

View clipView = findViewById(R.id.ClipView);
ClipDrawable clip = (ClipDrawable) clipView.getBackground();
clip.setLevel(1000);

ClipDrawable の Level に設定可能な数値は、最高 10,000 までです。

Clip Drawable

Scale Drawable

Drawable のレベルによって、別の Drawable の大きさを変化させる、XML のグラフィックリソースです。

<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:scaleGravity="center"
    android:scaleWidth="50%"
    android:scaleHeight="50%"/>

初期状態では、レベルが 0 に設定されているため、表示されません。 レベルを Java の側から設定すると、レベルに応じたスケールで表示されます。

View scaleView = findViewById(R.id.ScaleView);
ScaleDrawable scale = (ScaleDrawable) scaleView.getBackground();
scale.setLevel(1);

Scale Drawable

Shape Drawable

色やグラデーション情報を含む、幾何学的図形を XML で宣言するグラフィックリソースです。

<?xml version="1.0" encoding="utf-8"?>
<!-- 四角形グラフィックリソースの定義 -->
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
        <!-- solid: 塗りつぶし -->
	<solid
	    android:color="#f5f5f5"/>
        <!-- stroke: 枠線 -->
	<stroke
	    android:width="1dp"
	    android:color="#000000"/>
</shape>

Shape Drawable

Style Resource

View の各要素の属性値をまとめ、一定のフォーマットを規定するリソースです。 アプリ内で共通な UI を提供する際に活用していきます。

プロジェクトの新規作成直後には、デフォルトでstyles.xmlが配置されています。

アプリ内の View に共通な Style を定義する

<style>要素を利用して、共通に利用する View の属性を<item>要素に切り出し、<style>要素のname属性で、くくりだしたスタイルに名前をつけます。

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="BigTextViewStyle" parent="@android:style/Widget.TextView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">22sp</item>
    </style>
</resources>

このスタイルを適用するには、以下のように、各 View のstyle属性にスタイルへの参照を記述します。

<TextView
        style="@style/BigTextViewStyle"
        android:id="@+id/HelloWorld1"
        android:text="@string/hello_world"/>

継承

スタイルは継承して定義することも可能です。

システムで定義されたスタイルを継承する場合は、<style>要素のparent属性に、継承したいスタイルを指定します。

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="BigTextViewStyle" parent="@android:style/Widget.TextView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">22sp</item>
    </style>
</resources>

自分で定義したスタイルをさらに継承する場合は、parent属性ではなく、名前の付け方で継承を行います。 継承元のスタイルの名前をプレフィクスとして、ドット区切りで新しく定義するスタイルの名前を宣言することで、継承を行います。 継承は複数の階層にわたって行うことができます。

<!-- BigTextViewStyle を継承する -->
<style name="BigTextViewStyle.Red">
    <item name="android:textColor">#FF0000</item>
</style>
<!-- BigTextViewStyle.Red を継承する -->
<style name="BigTextViewStyle.Red.Bold">
    <item name="android:textStyle">bold</item>
</style>

メニュー(OptionsMenu と ContextMenu)の各種項目について規定するリソースです。 OptionsMenu は、デバイスに備わっている Menu キーで呼び出されるメニューのことです。 ContextMenu は、UI の長押しで呼び出されるメニューのことです。

<resources_name>menuですので、res/menu/ディレクトリ以下にリソースを配置します。 プロジェクトの新規作成直後には、デフォルトで、main.xmlが配置されています。

メニューの定義

<menu>要素をルートとして、子に<item>要素か、<group>要素を持ちます。 <item>要素は、メニュー項目1つ分に相当しますが、<item>要素の子要素に<menu>要素を持たせることで、サブメニューを構成することも可能です。 <group>要素では、複数の<item>要素をまとめて幾つかの状態を共有するグループを作ります。

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>
</menu>

OptionsMenu

OptionsMenu とは、メニューキーを押して表示するメニューのことです。 ICS 以降は、ActionBar の並びに入るメニュー要素として扱われます。

メニューリソースを用いて OptionsMenu を設定するには、Activity に定義された、onCreateOptionsMenu()メソッドをオーバライドし、MenuInflaterクラスを用いてメニューリソースにアクセスして利用します。

詳しい内容は、後の章で解説します。

public class MyActivity extends Activity {
    // do something...

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }
}

ContextMenu

ContextMenu とは、View を長押しした時に表示するメニューのことです。 OptionsMenu と同様、メニューリソースを用いて ContextMenu を設定するためのonCreateContextMenu()メソッドが Activity に用意されています。

ContextMenuは、明示的に View に ContextMenu を適用する必要があります。

その実態は、View に長押し状態を監視する Listener をセットし、そのコールバックを Activity の onCreateContextMenu() で受け付けるようにするものです。 このため、Activity への参照を他のオブジェクトが持つので、適切なタイミングでこのコールバックを受け付けないようライフサイクルの管理をする必要があります。

詳しい内容は、後の章で解説します。

public class MyActivity extends Activity {
    // do something...

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        getMenuInflater().inflate(R.menu.main, menu);
    }
}

Color State List Resource

UI の状態に応じた Color 要素を管理するカラーリソースです。 XML で、状態に対応する Color への参照を宣言します。

基本的な要素は、State List Drawable と同じ物を使用します。 カラーリソースとして宣言するので、<item>要素の属性には、android:colorを設定します。

State List Drawable ではグラフィックリソースでしたが、Color State List Resource はカラーリソースのため、background などのグラフィックリソースへの参照を要求する属性には適用できません。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- View が押された状態の Drawable -->
    <item android:color="#696969" android:state_pressed="true"/>
    <!-- View が通常の状態の Drawable -->
    <item android:color="#f5f5f5"/>
</selector>
<!-- カラーリソースなので、android:background属性には適用できない -->
<Button
    android:id="@+id/ColorStateListButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@color/sample_color_state_list"
    android:text="@string/hello_world"
    android:textSize="16sp"/>

Value Resource

アプリで利用する各種値(整数値や真偽値、寸法値、色など)も、XML に定数値として定義できます。

Integer

<resources>要素をルートにして、その子として<integer>要素を宣言していきます。 String Resource として数字を定義することも可能ですが、リソースから読み出す際にInteger.parseInt(String)する必要が有る為、Integer として扱う方が良いです。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 個別の値を定義する -->
    <integer name="DefaultEggs">1</integer>
    <integer name="DefaultBooks">3</integer>
    <integer name="DefaultPickaxe">100</integer>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Resources オブジェクトを介して取得する
        int eggs = getResources().getInteger(R.integer.DefaultEggs);
    }
}

Integer Array

<string-array>と同様の構造です。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer-array name="Periods">
        <item>1</item>
        <item>2</item>
        <item>3</item>
        <item>4</item>
    </integer-array>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Resources オブジェクトを介して取得する
        // integer-array の取得
        int[] integers = getResources().getIntArray(R.array.Periods);
    }
}

Typed Array

<string-array><integer-array>以外の、他の様々な型を配列に出来るものです。

<array>要素に、<item>を子要素としてぶら下げ、この中身を他のリソースの参照とします。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- String や Integer 以外のものでも配列にできる -->
    <array name="Drawables">
        <item>@drawable/ic_launcher</item>
    </array>
    <array name="Colors">
        <item>@color/Red</item>
        <item>@color/Green</item>
        <item>@color/Blue</item>
    </array>
    <!-- 異なる型のものを混ぜても良いが、Java のコード上で扱う際に、場所と型を気をつけないといけないので注意 -->
    <array name="MixedArray">
        <item>@drawable/ic_launcher</item>
        <item>@color/Blue</item>
    </array>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。
異なる型のものを混ぜた場合は、型に注意しながら取り扱います。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // typed-array の取得
        TypedArray colors = getResources().obtainTypedArray(R.array.Colors);
        int color2 = colors.getColor(0, Color.BLACK);

        TypedArray drawables = getResources().obtainTypedArray(R.array.Drawables);
        Drawable drawable = drawables.getDrawable(0);

        TypedArray mixed = getResources().obtainTypedArray(R.array.MixedArray);
        Drawable drawable2 = mixed.getDrawable(0); // ここで違う型のものを取り出そうとすると実行時例外でクラッシュ
        int color3 = mixed.getColor(1, Color.BLACK);
    }
}

Boolean

<resources>要素をルートにして、その子として<bool>要素を宣言していきます。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isCompany">true</bool>
    <bool name="isPerson">false</bool>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // boolean の取得
        boolean bool = getResources().getBoolean(R.bool.isCompany);
    }
}

Dimension

寸法を定義するリソースです。 View の大きさ(dp(density-independent pixel), px(pixel), pt(point), mm(milli-meter), in(inch))の他、文字サイズ(sp(scale-independent pixel))もこのリソースとして扱います。

このリソースは、プロジェクトの新規作成直後に、dimens.xmlというファイル名でデフォルトで用意されています。

Java のコードで読みだした場合、型は float 型となります。

<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

    <!-- 文字の大きさも定義可能 -->
    <dimen name="TitleSize">16sp</dimen>
    <dimen name="BodySize">14sp</dimen>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // dimension の取得
        float titleDim = getResources().getDimension(R.dimen.TitleSize);
    }
}

Color

色コードを定義するリソースです。 色コードに名前をつけて管理することが可能になります。

色コードの定義は 16 進数表記で行います。

Java のコードで読みだした場合、int 型整数値として扱われます。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="Red">#FF0000</color>
    <color name="Green">#00FF00</color>
    <color name="Blue">#0000FF</color>
</resources>

Activity や Fragment などの Context を持つところからアクセスする場合は以下のようにします。

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // color の取得
        int color = getResources().getColor(R.color.Blue);
    }
}

ID

レイアウトなどでandroid:id属性に指定する ID をまとめるリソースです。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item type="id" name="HelloWorld"/>
    <item type="id" name="Hoge"/>
</resources>

Animation Resource

アニメーションには2つの種類があります。

1つはプロパティアニメーション、もう1つはビューアニメーションです。

Property Animation

背景色を変化させたり、アルファ値を変化させたりと、対象のプロパティを操作してアニメーションに見せるものです。 HoneyComb 以降に導入された、新しいアニメーション方式です。

View Animation

View そのものを移動させたり、拡大縮小、回転させるアニメーションです。

アニメーションの種類には、以下のものがあります。

Alpha

アルファ値のアニメーションです。これにより、フェードインやフェードアウトを実現出来ます。

XML では、<alpha>要素として扱います。この要素の属性として、以下のものが用意されています。

android:fromAlpha
アニメーション開始時のアルファ値
android:toAlpha
アニメーション終了時のアルファ値
Scale

拡大縮小のアニメーションです。

XML では、<scale>要素として扱います。この要素の属性として、以下のものが用意されています。全てを設定する必要はなく、アニメーションしなくてもよい属性は宣言しなくても構いません。

android:fromXScale
アニメーション開始時の、横方向の拡大率です。1.0 を基準に拡大率を決めます。
android:toXScale
アニメーション終了時の、横方向の拡大率です。1.0 を基準に拡大率を決めます。
android:fromYScale
アニメーション開始時の、縦方向の拡大率です。1.0 を基準に拡大率を決めます。
android:toYScale
アニメーション終了時の、縦方向の拡大率です。1.0 を基準に拡大率を決めます。
android:pivotX
拡大の中心点のX座標です。指定しないと 上端 になります。
android:pivotY
拡大の中心点のY座標です。指定しないと 左端 になります。
Translate

平行移動のアニメーションです。

XML では、<translate>要素として扱います。この要素の属性として、以下のものが用意されています。
単位に使う % は、自分の大きさに対するパーセンテージとなります。単位を %p とした場合は、アニメーションを適用する要素の親要素に対するパーセンテージとなります。単位を付けない場合は、ピクセル値として扱われます。

android:fromXDelta
アニメーション開始時の X 座標です。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定できます。
android:toXDelta
アニメーション終了時の X 座標です。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定できます。
android:fromYDelta
アニメーション開始時の Y 座標です。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定できます。
android:toYDelta
アニメーション終了時の Y 座標です。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定できます。
Rotate

回転のアニメーションです。

XML では、<rotate>要素として扱います。この要素の属性として、以下のものが用意されています。

android:fromDegrees
アニメーション開始時の角度です。
android:toDegrees
アニメーション終了時の角度です。
android:pivotX
回転の中心点の X 座標です。
android:pivotY
回転の中心点の Y 座標です。

これらのアニメーションは、単一に宣言することもできますが、複数のアニメーションを組み合わせたアニメーションとして宣言することもできます。

複数のアニメーションを組み合わせる場合、<set>要素を親にして、複数のアニメーションを子要素にします。

また、すべての要素には、以下の様な属性が用意されています。

android:duration
アニメーションを再生する時間です。millisecond 単位で指定します。
android:repeatMode
アニメーションが終了した時に、アニメーションを最初から再開するか、最後から最初へ戻るようにするかを設定します。
この設定が有効になるのは、後述するandroid:repeatCount属性が 0 以上か、若しくは infinite に設定された時のみです。
デフォルト値では、アニメーションを最初から再開するように設定されます。
android:repeatCount
アニメーションを繰り返す回数です。infinite と設定することで、無限に繰り返すようにもできます。
android:startOffset
アニメーションのスタートの遅延時間です。指定した時間(msec)だけ遅延させることができます。
<?xml version="1.0" encoding="utf-8"?>
<!-- 回転と平行移動を同時に行うアニメーション -->
<set
    xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 回転は無限回 -->
    <!-- アニメーションする View のちょうど真ん中を中心に一周する -->
    <rotate
        android:duration="1000"
        android:repeatCount="infinite"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <!-- 平行移動は 1 回だけ -->
    <!-- アニメーションする View の親の 40% の位置に移動する -->
    <translate
        android:duration="1000"
        android:repeatCount="0"
        android:toXDelta="40%p"
        android:toYDelta="40%p"/>
</set>

アニメーションの適用は、Java のコードから行います。

View textView = findViewById(R.id.TextView1);

// Animation Resource を読み込んで、Animation オブジェクトを得る
Animation animation = AnimationUtils.loadAnimation(this, R.anim.sample_animation);
// Animation オブジェクトを View に渡して、アニメーションを開始する
textView.startAnimation(animation);

Raw(Binary) Resource

最適化をしない画像や、音声、動画等のバイナリデータリソースです。 バイナリデータを取り扱うため、InputStreamオブジェクトを介してリソースへアクセスします。

ファイル名がリソースの一意な ID となりますので、Java の文法に反するファイル名はエラーとなります。

// ファイル名がリソースの一意な ID として扱われる
InputStream in = getResources().openRawResource(R.raw.ファイル名);

多様なデバイスへの対応

Android OS を搭載する端末は、とてもたくさんの種類があり、使用している言語、解像度、画面の大きさ、向きなど、ハードウェアのスペックに限らず、多種多様な状況・状態が想定されます。
端末ごとに apk を分けて作ることも不可能ではありませんが、現実的には無理があります。
また、状態に応じたリソースの使い分けを自分たちで全てハンドリングするのも、とても大変な作業になってしまいます。

そこで Android フレームワークでは、Context を通してリソースへアクセスする設計によって、リソースを使う側からは単一の方法でリソースの取得ができるような仕組みを実現しています。
リソースの提供側は、端末のスペック・状況・状態に応じたリソースを用意するだけで、システムが自動で適切なリソースを選択してくれるようになります。

その仕組みを利用する上で重要なものが、リソースディレクトリの命名規則<resources_name>-<configuration_qualifier>のなかの、<configuration_qualifier>です。

English Locale Resource

Japanese Locale Resource

French Locale Resource

この項目では、最も重要なロケール、解像度、画面の向きの3つの対応について解説します。

<configuration_qualifier>

複数の<configuration_qualifier>を付与することができ、これによって、様々なデバイスへの対応をしていきます。

ただし、<configuration_qualifier>の付与には順序が決められています。これに従わない場合、意図した動作をしなくなります。

下記に順番の一例を示します。上にあるものほど最初に付与することになります。

  1. Language and Region
    • 言語
    • jaenfrなどと指定する
  2. Smallest Width
    • ディスプレイの短辺の大きさ
    • sw600dpsw720dpなど、sw<N>dpの形式で、dpの単位で指定する
  3. Screen Orientation
    • 画面の向き
    • landまたはport
  4. Screen Pixel Density
    • ピクセル密度
    • ldpimdpihdpixhdpixxhdpinodpitvdpiなどと指定する。
  5. Platform Version
    • OS のバージョン
    • v4v7などと指定する。数字は API Level のものを使う。

この順番に従うと、例えばvalues-v4-enという名前は不正で、values-en-v4が正しい、と言うことになります。

ロケール

端末で使用している言語に応じてリソースを定義することができます。

ISO 639-1 で定義された言語コードを使用することが出来、またオプショナルな値として、ISO 3166-1-alpha-2 の地域コードも使用出来ます。

何も指定しない場合は、デフォルトのリソースとして扱われ、<configuration-qualifier>で指定した言語のリソースから漏れたものは全てデフォルトのリソースが使用されます。

言語 ディレクトリ
日本語 values-ja
英語 values-en
フランス語 values-fr

高解像度スクリーン

解像度に合わせてリソースを定義することができます。

解像度の低い順に、ldpimdpihdpixhdpixxhdpiなどが定義されています。最近の端末だとxhdpiのものが主流になりつつあります。

Drawable Resource で、解像度ごとに png ファイルを分ける、という用途で頻繁に使用します。

解像度 ディレクトリ
ldpi drawable-ldpi
mdpi drawable-mdpi
hdpi drawable-hdpi
xhdpi drawable-xhdpi
xxhdpi drawable-xxhdpi

画面回転

画面の向きによってもリソースを定義することができます。特に、レイアウトを縦画面と横画面で作り分ける、などの際に便利です。

向き ディレクトリ
layout-land, drawable-land
layout_port, drawable-port

実習

AndroidStudio/practice/fundamentals/3rd/ResourceManagement/build.gradleを開き、 以下の実習に取り組んでください。

String Resource

  1. 日本語のリソースを 5 つ定義して、string_practice1.xml でそれらを表示する TextView を配置してください。
  2. 定義した 5 つの日本語リソースに対応する英語リソースを宣言してください(プロジェクトは実習 1 と同じものを使う)。
  3. 最初に定義された日本語リソースのフォーマットに基いて、動的に文章を生成して TextView に表示してください。

Drawable Resource

  1. 四角形の塗りつぶしの中に円を描く Drawable を XML で宣言してください。
  2. 上記の Drawable で利用する色を Value Resource に宣言してください(色は好みのものを使用して良く、プロジェクトは実習 1 と同じものにすること)。

Animation Resource

  1. 複数のアニメーションを組み合わせたアニメーションを作成し、任意の View に割り当ててください。

課題

String Resource

  1. 用意されている日本語リソースに対応する、英語の複数形の表現を宣言し、MainActivity に表示できるようにしてください。(使用するプロジェクト: AndroidStudio/assignments/fundamentals/3rd/StringResourceAssignment1/app/build.gradle)

Drawable Resource

  1. 実習で作った Drawable を利用し、下記の要件を満たす State List Drawable を作成して、Button に適用してください。(使用するプロジェクト:AndroidStudio/assignments/fundamentals/3rd/DrawableResourceAssignment1/app/build.gradle)
    • Button が押されていない時の Drawable
    • Button が押された時の Drawable
    • Button にフォーカスがあたった時の Drawable
    • 上記 3 つの状態に対応する異なる Drawable を宣言しておくこと
  2. 1 で作った Drawable を、画面の向きによって、下記の条件で切り替わるようにしてください。(1 と同じプロジェクトの中で実施する)
    • 縦と横で、色違いの見た目になれば良い