UIとしてActivityを持ったライブラリにユーザが見た目をカスタマイズできる機能を付けたかったので方法を調べました。
やりたいこと
- ライブラリは UI (Activity) を持っている
- 基本はデフォルトのデザインを使用する、ただしカスタマイズも可能にしたい
- カスタマイズはカラーパレットを定義するようなイメージにしたい
- テーマカラー
- メイン文字色
- etc
- ボタン画像なども変更したい
- ライブラリプロジェクトではなくMavenで配布したい
- ライブラリプロジェクトのリソースを書き換えてのカスタマイズはNG
これらを実現するためにThemeにカスタム項目を定義、利用者側でデフォルトのテーマをオーバーライドする方法を実現します。
ライブラリ側
res/values/attrs.xmlにカスタム項目を定義します。名前は自由です、コードから値を呼び出すときに使います。
<resources>
<declare-styleable name="CustomTheme">
<attr name="mainThemeColor" format="color"/>
<attr name="mainTextColor" format="color"/>
<attr name="mainScreenBackground" format="reference" />
</declare-styleable>
</resources>
カスタム項目を使用したtheme/styleを作成しカスタム項目を設定します。parentはお好きなものを、カスタム項目以外の値も設定しても構いません。
ここで設定した値がデフォルト値になります。
<resources>
<style name="DefaultLibraryTheme" parent="android:Theme">
<item name="mainThemeColor">#333333</item>
<item name="mainTextColor">#ffffff</item>
<item name="mainScreenBackground">@drawable/default_background</item>
</style>
</resources>
レイアウトでカスタム項目の値を使用するには?attr/[カスタム項目]
という形式で記述します。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?attr/mainScreenBackground">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test style"
android:layout_gravity="center_vertical"
android:textColor="?attr/mainTextColor"/>
<View
android:background="?attr/mainThemeColor"/>
</LinearLayout>
コードから値を利用したい場合は、context#obtainStyledAttributes
でTypedArrayを取得、カスタム項目のR.styleable.〜
を使用して値を取得します。
TypedArray array = context.obtainStyledAttributes(R.styleable.CustomTheme);
view.setBackground(array.getDrawable(R.styleable.CustomTheme_mainThemeColor));
array.recycle();
利用者側
ライブラリを使う側ではライブラリが用意しているデフォルトのテーマを継承してカスタムテーマを作ります。
デフォルト値が設定されているので変更したいところだけ記載すれば良いです。
<resources>
<style name="MyTheme" parent="DefaultLibraryTheme">
<item name="mainThemeColor">#ff0000</item>
<item name="mainScreenBackground">@drawable/my_main_background</item>
</style>
</resources>
利用側のAndroidManifestでのActivityに作ったカスタムテーマを指定します。
<!-- カスタムテーマを適用したバージョン -->
<activity android:name=".HogeLibraryActivity" android:theme="@style/MyTheme">
<!-- デフォルトテーマを適用したバージョン
<activity android:name=".HogeLibraryActivity" android:theme="@style/DefaultLibraryTheme">
-->
おわり
カスタム項目には色やDrawableだけじゃなくstyleも指定できるので、この辺りをうまく使えばかなりカスタマイズ性を高められそうです。
ただ、ライブラリの用途にもよりますがデフォルトで用意するテーマについては、利用側アプリのテーマに合わせられるようparentを複数用意したほうが良いかもしれません。