米国時間の 10 月 17 日に Android 5.0 SDK がリリースされました。新しい UI ウィジェットや、デザイン性にこだわったビジュアル言語であるマテリアル デザインを含んでいます。過去バージョンを搭載した Android デバイスにも最新のデザインを提供できるよう、AppCompat の大型アップデート、および新たなライブラリ(RecyclerViewCardViewPalette)の追加を行い、ライブラリを拡張しました。

本記事では AppCompat の新しくなった点と、アプリ開発においてマテリアル デザインを取り入れる方法について見ていきます。

AppCompat に新たに追加された機能

AppCompat(別名 ActionBarCompat)は Android 4.0 の ActionBar API を Gingerbread 搭載デバイスに対応させるためのバックポートとしてはじまり、バックポートとフレームワーク共通の API レイヤーを提供していました。AppCompat v21 は Android 5.0 に対応した機能と API をお届けします。

このリリースで、Android は新しい Toolbar ウィジェットを導入します。これは、より正確なコントロールと柔軟性を可能にする Action Bar パターンを一般化したものです。Toolbar はビュー階層内に存在しているので、他のビューとの共存や、アニメーション、スクロールイベントへの反応といったことが簡単にできます。Activity の Action Bar として設定することもできるので、通常のオプション メニューのアクションをその内部に表示させることも可能です。

最新の AppCompat はここ数週間でいくつもの Google アプリ(Play ストアや Play ニューススタンドなど)のアップデートに含まれているので、すでにみなさんも使用されているはずです。上記の画像の Google I/O Android アプリ(オープンソース)もすでに最新の AppCompat に対応しています。

セットアップ

Gradle を使用している場合は、build.gradle ファイルに appcompat を依存関係(dependencies)として追加します。

dependencies {
    compile "com.android.support:appcompat-v7:21.0.+"
}

新規にはじめる場合

現在 AppCompat を使用していないか、これから新規にはじめる場合の設定方法です。
  • すべての Activity は ActionBarActivity から拡張されている必要があります。ActinBarActivity は v4 サポートライブラリの FragmentActivity から拡張されているので、引き続き fragment を使用することができます。
  • Action Bar/Toolbar を使用するテーマは必ず Theme.AppCompat を継承する必要があります。LightNoActionBar などのバリエーションもあります。
  • Action Bar に表示される内容(Toolbar 内のリストナビゲーションのための SpinnerAdapter など)を inflate するときには、必ず getSupportActionBar().getThemedContext() 経由で取得した Action bar のテーマの内容を使用してください。
  • MenuItem に対して Action に関連したコールを行う場合は、必ず MenuItemCompat 内の static メソッドを使用してください。
より詳細な情報は、AppCompat の総合的なガイド Action Bar API guide を参照してください。

既存のセットアップからの移行

ほとんどのアプリでは、values/ にテーマを 1 つ宣言するだけで大丈夫です。

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    <!-- AppCompat  actionBarStyle を設定 -->
    <item name="actionBarStyle">@style/MyActionBarStyle</item>
    
    <!-- AppCompat  color theming attrs を設定 -->
    <item name=”colorPrimary”>@color/myawesomered</item>
    <item name=”colorPrimaryDark”>@color/myawesomedarker_red</item>
    
    <!-- 他の属性 -->
</style>

これで values-v14 以上の Action Bar のスタイルはすべて削除しても大丈夫です。

テーマ

AppCompat は新しい Color Palette のテーマの属性をサポートしており、あなたのブランドに合った主要色と強調色のテーマを容易にカスタマイズできます。

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
  <!-- colorPrimary is used for the default action bar background -->
  <item name=”colorPrimary”>@color/my_awesome_color</item>

  <!-- status bar には colorPrimaryDark が使用されます -->
  <item name=”colorPrimaryDark”>@color/my_awesome_darker_color</item>

  <!-- ウィジェットに色合いを付ける colorControlActivated のデフォルト値として colorAccent が使用されます -->
  <item name=”colorAccent”>@color/accent</item>

  <!-- 他にも colorControlNormalcolorControlActivated
         colorControlHighlight  colorSwitchThumbNormalを設定できます -->
</style>

これらの属性を設定すると、AppCompat は自動的に API 21以上のフレームワーク属性の値に影響し、ステータスバーや Overview (履歴)のエントリーの色が自動で設定されます。

旧来のプラットフォームでは、 AppCompat は可能な箇所ではカラーテーマをエミュレートします。現時点では Action Bar といくつかのウィジェットに色を付けることに限定されています。

ウィジェットの色付け

Android 5.0 を搭載したデバイスでは、すべてのウィジェットは上述のカラーテーマ属性を使用して色付けされています。Lollipop でこれを可能にしているのは2つの機能です。drawable tinting と  drawable におけるリファレンステーマ属性(?attr/fooの形式)です。

5.0 より前のバージョンの Android では、AppCompat は UI ウィジェットのサブセットに対して類似の機能を提供します。
  • AppCompat の Toolbar で提供するすべて(アクションモードなど)
  • EditText
  • Spinner
  • CheckBox
  • RadioButton
  • Switch(新しい android.support.v7.widget.SwitchCompat を使用してください)
  • CheckedTextView
これらが機能するために特別何かを設定する必要はありません。通常通りレイアウト内でこれらのコントロールを使用すれば、あとはAppCompat が処理してくれます(いくつかの注意事項がありますので、最下部の FAQ を参照してください)。

Toolbar ウィジェット


Toolbar は AppCompat で完全にサポートされ、フレームワーク ウィジェットと同等の機能と API をもちます。AppCompat では、Toolbar は android.support.v7.widget.Toolbar クラスに組み込まれています。Toolbar を使用するには2つの方法があります。
  • Toolbar を Action Bar のように使用する。これはメニュー inflate や選択、ActionBarDrawerToggle のような、既存の Action Bar 機能を使用したいけど外見をより細かくコントロールしたい、といったときに有効です。
  • スタンドアローン Toolbar を使用する。これは1度に複数の toolbar を表示したり、画面の全幅に満たない toolbar を表示したりといった、 Action Bar では対応できないようなパターンを使用したいときに有効です。

Action Bar

Toolbar を Action Bar のように使用するには、まずあらかじめ外観が提供されている Action Bar を無効にします。Theme.AppCompat.NoActionBar(もしくはこれのバリエーション)からテーマを拡張するのが最も簡単な方法です。

次に、Toolbar インスタンスを作成します。(通常、レイアウトを指定する XML を使用します)

<android.support.v7.widget.Toolbar
    android:id=”@+id/my_awesome_toolbar”
    android:layout_height=”wrap_content”
    android:layout_width=”match_parent”
    android:minHeight=”?attr/actionBarSize”
    android:background=”?attr/colorPrimary” />

例としては、高さ、幅、背景などを望むままに設定できます。ToolbarViewGroup なので、スタイルも配置も自由に行えます。
そして ActivityFragment にて、Toolbar が Action Bar として機能するように設定します。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

   Toolbar toolbar = (Toolbar) findViewById(R.id.myawesometoolbar);
    setSupportActionBar(toolbar);
}

これで、通常のオプション メニュー コールバックを経由して、すべてのメニュー アイテムは Toolbar に表示されます。

スタンドアローン

スタンドアローン モードの違いは、Toolbar を Action Bar として機能させない点です。これにより、すべての AppCompat テーマを適用することができ、予め外観が提供されている Action Bar を無効にする必要がありません。
スタンドアローン モードでは、Toolbar のコンテンツやアクションを手動で入力しなくてはいけません。たとえばアクションを表示させたいのであれば、メニューを inflate する必要があります。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

   Toolbar toolbar = (Toolbar) findViewById(R.id.myawesometoolbar);

   // メニューアイテムのクリックに対応するために、OnMenuItemClickListener を設定
    toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            // メニューアイテムに対応
            return true;
        }
    });

   // toolbar に表示されるようにメニューを inflate
    toolbar.inflateMenu(R.menu.yourtoolbarmenu);
}

Toolbar でできることは他にもたくさんあります。詳細については Toolbar API reference を参照してください。

スタイル

Toolbar のスタイルは通常の Action Bar とは異なっており、ビューを直接設定します。
下記は Toolbar を Action Bar として使用しているときに採用すべき基本的なスタイルです。

<android.support.v7.widget.Toolbar  
   android:layoutheight="wrapcontent"
   android:layoutwidth="matchparent"
   android:minHeight="?attr/actionBarSize"
   app:theme="@style/ThemeOverlay.AppCompat.ActionBar" /> 
app:theme 宣言によって、テキストとアイテムが単色塗りつぶしとなります。(100% 不透明な白色など)

DarkActionBar

レイアウト属性を使用することで、Toolbar のインスタンスのスタイルを直接設定できます。「DarkActionBar」(コンテンツは暗く、オーバーフロー メニューは明るい) のように見える Toolbar を作成するには、適切なテーマ属性と popupTheme 属性を設定します。

<android.support.v7.widget.Toolbar
   android:layoutheight=”wrapcontent”
   android:layoutwidth=”matchparent”
   android:minHeight=”@dimen/tripleheighttoolbar”
   app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
   app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

SearchView ウィジェット

AppCompat は Lollipop で刷新された SearchView API を提供しますので、今までよりもカスタマイズ性とスタイル設定に優れています。これからは旧来の searchView* テーマ属性の代わりに、Lollipop 式の構造を使用します。
SearchView のスタイル設定方法は以下の通りです。

values/themes.xml:

<style name=”Theme.MyTheme parent=”Theme.AppCompat”>
    <item name=”searchViewStyle”>@style/MySearchViewStyle</item>
</style>
<style name=”MySearchViewStyle parent=”Widget.AppCompat.SearchView”>
    <!-- 検索クエリ部分(EditText など)の背景 -->
    <item name="queryBackground">...</item>
    <!-- アクション部分(voicesubmit など)の背景 -->
    <item name="submitBackground">...</item>
    <!-- Close ボタンアイコン -->
    <item name="closeIcon">...</item>
    <!-- Search ボタンアイコン -->
    <item name="searchIcon">...</item>
    <!-- Go/commit ボタンアイコン -->
    <item name="goIcon">...</item>
    <!-- Voice search ボタンアイコン -->
    <item name="voiceIcon">...</item>
    <!-- クエリ サジェスチョン行に表示される Commit アイコン -->
    <item name="commitIcon">...</item>
    <!-- クエリ サジェスチョン行の レイアウト -->
    <item name="suggestionRowLayout">...</item>
</style>

ほとんどのアプリにおいてはデフォルトのままでも正常に機能しますので、これらをすべて(あるいは 1 つも)設定する必要はありません。

Toolbar が今ここに…

この記事が AppCompat の使いはじめと、素晴らしいマテリアル アプリの製作の一助となれれば幸いです。AppCompat をはじめとするサポート ライブラリについての質問や、ドキュメントを増やすべき分野がありましたら、コメント欄や Google+、Twitter などでお知らせください。

FAQ

Lollipop 導入前のデバイスで EditText(もしくは前述のウィジェットの1つ)が正しく色付けされていないのはなぜですか?
AppCompat のウィジェット色付けは、レイアウト inflation を感知して、色付けに対応した特別なウィジェットを代わりに差し込む仕組みになっています。ほとんどの場合はこれで正しく機能しますが、下記のような例外ケースも考えられます。
  • 当該ウィジェットがカスタマイズされている(つまり EditText を拡張している)
  • LayoutInflater なしで EditText を作成している(つまり新規の EditText() をコールしている)
色付けに対応した特別なウィジェットは未完成のため、現在隠されています。今後変わる可能性があります。

Lollipop 導入前のデバイスでは特定のウィジェットにマテリアル スタイル化されていないのはなぜですか?
現時点まででアップデートされたのは、最も広く使われているウィジェットだけだからです。今後の AppCompat リリースとともに増えていきます。

android:windowContentOverlay は null に設定しているのに、Android Lollipop で私の Action Bar にシャドウがあるのはなぜですか?
Lollipopでは、新しい Elevation API を使って Action Bar にシャドウを付与しています。取り除くには、getSupportActionBar().setElevation(0) をコールするか、Action Bar スタイルで Elevation 属性を設定します。

Lollipop 導入前のデバイスではリップル効果がないのはなぜですか?
RippleDrawable の動作は Android 5.0 の新しい RenderThread に大きく依存します。現状 5.0 より前のバージョンの Android では、パフォーマンス最適化のため RippleDrawable は含まれていません。

Preferences で AppCompat を使用するにはどうしたらいいですか?
API v11 以上のデバイスでは、引き続き ActionBarActivity で PreferenceFragment を使用できます。それより古いデバイスではマテリアル スタイル化されていない、通常の PreferenceActivity を提供する必要があります。

Posted by 荒木佑一 Developer Relations Team