つぶしの効く Android のスタイルテクニック


Android アプリ全体で統一したデザインスタイルがあると、つぶしが効いて良いですよね。
そのための仕組みとして、Android ではテーマというものが設けられています。テーマを用いることで、アプリケーション全体の配色を決めたり、文字のスタイルを決めたりすることができるようになります。

一つのテーマを全体に適用するだけでよければそれはそれで良いのですが、実際問題としては複数のテーマを画面ごとに使い分けることもよくある話かと思います。この画面はフルスクリーンで ActionBarを消すけど、別の画面ではActionBarを出す、みたいな。

さて、複数のテーマを使う場合、たとえば、Light と Dark でボタンの色みを変えたい、という事が起こります。色合いがよく似ているならともかく、Light と Dark のように大きな違いがある場合は、色の調整をしたほうが良いでしょう。

また、テーマは各種のスタイルを統合するための仕組みでもあります。Buttonの見た目、TextViewの文字のスタイルなど、目的別にスタイルを切り出すことによって、それぞれのスタイルに命名をすることができます。テーマごとにそのスタイルを切り替えられるようにしておけば、修正も楽になることでしょう。

Theme で使える属性値

このファイルに、デフォルトで定義されている属性値がリストアップされています。というか、その XML そのものです。
おびただしい量の属性値があるので、そのすべてを使いこなすのは至難の業かもしれませんが、例えばボタンのスタイルを変えたければ、自分のstyles.xmlにあるテーマに、以下の行を追加すればよいのです。


<resources>
  <style name="MyTheme" parent="android:Theme.Light">
    <item name="android:buttonStyle">@style/MyButtonStyle</item>
  </style>

  <style name="MyButtonStyle" parent="android:Widget.Button">
  </style>
</resources>

これを、テーマごとに使い分けるので


<resources>
  <style name="MyTheme" parent="android:Theme.Light">
    <item name="android:buttonStyle">@style/MyLightButtonStyle</item>
  </style>
  <style name="MyAnotherTheme" parent="android:Theme">
    <item name="android:buttonStyle">@style/MyDarkButtonStyle</item>
  </style>

  <style name="MyLightButtonStyle" parent="android:Widget.Button">
  </style>
  <style name="MyDarkButtonStyle" parent="android:Widget.Button">
  </style>
</resources>

となります。これで、すべてのボタンがテーマによって指定されたスタイルになるので、ボタンごとにstyle属性値を設定する必要がなくなりました。

属性値の解決を遅延させる

この表現が正しいのかよく分かりませんが、直接属性値にスタイルdrawablestringなどへの参照を設定するのではなく、一旦別の箱を用意してそれを参照し、その箱の実態はテーマかどこかで決めるような、ちょっとまどろっこしいですがそんなやり方があります。

attrs.xml

<resources>
  <attr name="my_drawable" format="reference"/>
</resources>

を用意しすると、my_drawableという独自の属性が定義されます。これを用いると、

styles.xml

<resources>
  <style name="MyTheme" parent="android:Theme.Light">
    <item name="my_drawable">@drawable/my_icon_1</item>
  </style>
  <style name="MyAnotherTheme" parent="android:Theme">
    <item name="my_drawable">@drawable/my_icon_2</item>
  </style>
</resources>

と言うように宣言でき、レイアウト上では、

someone.xml

<ImageView
  ...
  src="?attr/my_drawable"
  .../>

のように、?attr/属性名と表記することで、テーマによって画像が切り替えられるようになります。これをスタイルにまとめる属性に応用すれば、Android Framework のテーマがやっていることと同じことを、自分でガシガシ作りこんでいくことができます。

継承

テーマスタイルには継承の考え方があります。
その方法には2種類あり、ひとつにはparent属性を用いる方法、もうひとつには、.区切りの命名規則による方法です。

parent属性は簡単で、親にしたいテーマスタイルを属性値とすればよいだけです。
ただし、公式のリファレンスに曰く、この方法は「フレームワークのリソースを親として参照する場合に限る」と。

しかし、自分で用意したスタイルテーマも継承したい場面があるでしょう。そこで.区切りの命名規則を用います。

styles.xml

<resources>
  <style name="MyLightButtonStyle" parent="android:Widget.Button">
  </style>
  <style name="MyLightButtonStyle.Hoge">
  </style>
</resources>

以上のように作ると、MyLightButtonStyleの属性をMyLightButtonStyle.Hogeが引き継ぎ、かつMyLightButtonStyle.Hoge独自の拡張ができるようになります。名前空間を区切る間隔で継承による属性値の引き継ぎができるので、スタイルの整理をする際によく用いられます。

まとめ

同じ画面でのテーマの切り替えがそれほど頻繁にあるかどうかはアプリの仕様に依存することと思いますが、往々にしてとっ散らかって収集がつかなくなりがちなリソースも、これらのテクニックでうまく統合できるようになると、管理コストが減らせてよいですね。