2011/07/31

PhoneとTabletで設定メニューを共有する

Paplicoを作成していてふと気付いたことが。

Compatibility PackageにはPreferenceFragmentが無い!


PreferenceFragmentが使えるなら同じ設定画面を使い回すことが出来ると思ったのですが、どうやらPhone向けのPreferenceActivityとTablet向けの2ペインPreferenceActivityを別に作成する必要があるみたいです。
(注:ちゃんと調べてないので、もっと楽な方法があるのかも。知ってたら教えて下さい)



今回作成する設定メニューの構造はこちら


これをTabletで表示するとこんな感じ。


Phoneの方の見た目は省略(というか言わずもがな)。
Phoneでは設定画面のトップメージで「メニュー1」と「メニュー2」だけが表示される形になります。


今回のサンプルAPK及び作成したプロジェクトはこちら


・AndroidManifest.xml


今回利用するActivityは
・Main・・・PhoneかTabletかを判断して起動するメニューを分けるだけのActivity。

Phone用
・PreferenceHeader・・・スマートフォンで表示する設定メニューのトップページ。
・PreferenceActivity1・・・スマートフォンで表示する設定メニューの詳細ページ1
・PreferenceActivity1・・・スマートフォンで表示する設定メニューの詳細ページ2

Tablet用
・MainPreference・・・タブレットで表示する設定メニュー


・利用するXMLについて

まずはタブレットで利用するXMLについて。
タブレットでは2ペインのメニュー構成になっていますが、これを実現するのは非常に単純で、左ペインのヘッダー部分も右ペインの詳細メニューも共にXMLで構成することができます。

今回タブレットで使用する設定画面のXMLは全部で3つです。
・ヘッダー部分(左ペイン)
res/xml-xlarge-v11/preference_header.xml

このheaderというのはAPI11で追加されたPreferenceActivity$Headerのことで、もうちょっと詳しい使用例はこちらに載っています。
今回はheaderタグ内のfragmentに右ペインに表示するPreferenceFragmentのパスを指定しているだけですが、IntentでWebを開くとかヘッダーの左にアイコンを表示するとか、もっと色々出来るらしいです。
ただしこれはCompatibility Packageでも利用できないため、API11以降専用になります。
なおXMLファイルのフォルダから分かる通り、このXMLはXLARGE画面を持ったAPI11以降専用のXMLです。

・詳細1
res/xml/preference1.xml

PreferenceScreenが二つあるだけのいたって普通な設定画面XMLです。このXMLはスマートフォン、タブレット共用になります。
@string等のリソース詳細は割愛します。

・詳細2
res/xml/preference2.xml
詳細1と全く同じなので割愛します。


次にスマートフォンについて。
スマートフォンで利用する設定画面XMLも3つですが、詳細1・2はタブレットと共用です。スマートフォン専用で必要なのはトップページのヘッダー部分だけになります。

・ヘッダー部分
res/xml/preference_header.xml

ヘッダーを構成するPreferenceScreenが二つあり、それぞれクリックすると詳細のActivityを起動します。


・Javaについて

Androidで設定画面を利用する時にはPreferenceActivityのonCreateでaddPreferenceFromResourceを呼んで設定画面を定義したXMLを利用すると思います。今回利用するのもこの流れと全く同じなのですが、タブレットで2ペイン画面を構成するには右ペインにPreferenceFragmentを設置する必要があります。

PreferenceFragmentの利用方法はPreferenceActivityと基本的には同じで、

特に特別な処理する必要の無い設定画面であればこれだけです。
今回の趣旨は従来の、PreferenceFragmentを利用できないAndroid OSで如何に楽をして設定画面を作成するかになります。

どうすれば楽にPreferenceFragmentとPreferenceActivityの中身を融合できるのか。。。

・PreferenceWrapper.java

どちらかしか使えないので、それらから必要なメソッドを取得するクラス作ればいいじゃない!←結論
簡単な設定メニューを作成するだけであればaddPreferencesFromResource、findPreference、getStringさえ利用出来ればいいので、今回はこれらだけを含んだクラスを作成しました。


あとはこれを
・BasePreference.java

こんな感じの抽象クラスを作成して、これを実際のPreferenceActivityやPreferenceFragmentの中身にします。

・BasePhonePreferenceActivity.java

これを本当に作成すべきかは分かりませんが、こんな感じでPreferenceActivity/PreferenceFragment共に継承元のクラスを作成しておくと後でメンテがしやすい様な気がします。BasePreferenceFragmentは割愛します。


次に、タブレットでマルチペイン設定画面を構成する方法ですが、
・MainPreference.java

特に特別なことをしないならばこれだけでマルチペインの設定画面になります。
PreferenceActivity#onBuildHeadersでloadHeadersFromResourceに先程preference-headerをルートで作成したXMLを指定するだけです。各設定の詳細はPreferenceFragment内で行われるため、基本的にベースとなるPreferenceActivityでは何もする必要はありません。


設定画面をクリックしたりした際の挙動をどこかで記述する必要がありますが、それは先程紹介したBasePreferenceを継承したクラスの中で行います。
・Preference1.java

簡単な例となりますが、こんな感じ。普段PreferenceActivity#onCreateで行っている処理がこのクラスのonCreateで行います。まずaddPreferencesFromResourceメソッドを呼びXMLを指定し、その後実際の処理をつらつらと。


あとはこれを
・PreferenceActivity1.java

こんな感じで利用すれば、設定メニューが完成します。PreferenceFragmentを継承した方のクラスも全く同じ方法です。



簡単でしょ!

最後の方が雑?
じゃっかんめんどうくさくなっt