【Androidアプリケーションの設定画面を作ろう】PreferenceActivityで設定画面を作る方法
PreferenceActivityは設定画面を作るためのActivityです。
Android3.0(API レベル 11)を境に前と後で実装方針が大きく変化しています。
- Android3.0以前はPreferenceActivityを単体で使い設定画面を作成します。
- Android3.0以後は「ActivityとPreferenceFragment」や「PreferenceActivityとPreferenceFragment」を組み合わせて作成します。
新しい実装方法では設定画面はヘッダーリストペインとコンテンツペインの二つのペインで構成されます。
ヘッダーとはPreferenceFragmentを元に作られたPreferenceActivity.Headerのことを指します。このヘッダーを並べたリストをヘッダーリストと呼びます。
ヘッダーリストの項目をクリックすることでPreferenceFragment内で設定された設定項目がコンテンツペインに表示されます。
ヘッダーリストを定義する
ヘッダーリストはxmlファイルを使って定義します。ルートタグにはpreference-headersを使用します。このpreference-headersタグの子要素にheaderタグを並べることでヘッダーをリスト化することができます。
headerタグには下記の属性があります。
android:id | 識別するidを設定します。 |
android:icon | アイコン画像を画像リソースIDを指定します。 |
android:title | タイトルを設定します。 |
android:summary | ヘッダーリストの説明を設定します。 |
android:breadCrumbTitle | パンくずリストのタイトルを設定します。 |
android:breadCrumbShortTitle | パンくずリストの省略タイトルを設定します。 |
android:fragment | ヘッダーに対応するフラグメントを完全修飾名で指定します |
extraタグを設定することでandroid:fragmentに指定したFragmentに値を渡すことができます。 一方、intentタグを設定することでインテントからActivityを起動することができます。
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:id="@+id/setting_1" android:icon="@drawable/ic_info_black_24dp" android:title="設定 1" android:summary="summary" android:breadCrumbTitle="breadCrumbTitle" android:breadCrumbShortTitle="breadCrumbShortTitle" android:fragment="yona.mypreference.MyPreference1Activity$Prefs1Fragment"/> <header android:id="@+id/setting_2" android:icon="@drawable/ic_notifications_black_24dp" android:title="設定 2" android:summary="summary" android:breadCrumbTitle="breadCrumbTitle" android:breadCrumbShortTitle="breadCrumbShortTitle" android:fragment="yona.mypreference.MyPreference1Activity$Prefs2Fragment"> <extra android:name="header" android:value="value from xml"/> </header> <header android:icon="@drawable/ic_info_black_24dp" android:title="設定 3"> <intent android:action="android.settings.SYNC_SETTINGS" /> </header> </preference-headers>また、上記のandroid:fragment属性に設定されているクラスを内部クラスとして定義します。
これらのPreferenceActivityで使用されるFragment達は事前に登録されている必要があります。
boolean isValidFragment(String fragmentName)をオーバーライドします、引数はフラグメントの名前が渡されます。
この名前を元に正当なフラグメントの場合はtrueを、不正なフラグメントの場合はfalseを返却するように実装します。
public static class Prefs1Fragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_general); } } public static class Prefs2Fragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle arguments = getArguments(); addPreferencesFromResource(R.xml.pref_data_sync); } } @Override protected boolean isValidFragment(String fragmentName) { return Prefs1Fragment.class.getName().equals(fragmentName) || Prefs2Fragment.class.getName().equals(fragmentName); }
設定画面を作成する
ヘッダーリストを作成するにはvoid onBuildHeaders(ListPreferenceActivity#onBuildHeadersはPreferenceActivityがヘッダーリストを作成するタイミングで呼ばれます。
PreferenceActivity#onBuildHeadersの中でvoid loadHeadersFromResource(int resid, List
第一引数にはヘッダーリストを定義したxmlファイルリソースIDを渡します。第二引数にはPreferenceActivity#onBuildHeadersの引数で渡されたインスタンスを渡します。
また、ヘッダーリストが作成された後にPreferenceActivity.Header onGetInitialHeader()が呼ばれます。
onGetInitialHeaderをオーバーライドすることで最初に表示する設定画面を変更することができます。
@Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } @Override public Header onGetInitialHeader() { Header header = new Header(); header.fragment = Prefs2Fragment.class.getName(); header.breadCrumbTitle = "onGetInitialHeader"; return header; }また、PreferenceActivityがヘッダーリストを使っているかどうかはboolean hasHeaders()を使用します。 PreferenceActivity#hasHeadersはヘッダーリストを使用している時にtrueを返却し、使用していない時にfalseを返却します。
ペインのモードを変更する
PreferenceActivityで作ることができる設定画面には二つの表示モードがあります。シングルペインモードとマルチペインモードの二つの表示モードがあります。
シングルペインモードは最初の画面にヘッダーリストが表示され、ヘッダーリストの項目をクリックした時に次の画面が表示され、コンテンツペインが表示されます。
マルチペインモードはヘッダーリストペインとコンテンツペインを並べて表示され、ヘッダーリストから選択したヘッダーに対応するPreferenceFragmentがコンテンツペインに配置されます。
モードを切り替える時はboolean onIsMultiPaneをオーバーライドします。
今回は画面が縦の時はシングルペインモード、横の時はマルチペインモードになるようにします。
@Override public boolean onIsMultiPane() { int orientation = getResources().getConfiguration().orientation; return orientation == Configuration.ORIENTATION_LANDSCAPE; }また、ペインモードを知るにはboolean isMultiPaneを使用します。現在、マルチペインの場合はtrueを返却し、 シングルペインの場合はfalseを返却します。
ヘッダーのクリックを検知する
void onHeaderClick(PreferenceActivity.Header header, int position)はヘッダーリストをクリックした時に呼ばれるメソッドです。そのため、ヘッダーがクリックされた時に何かをしたい時はPreferenceActivity#onHeaderClickをオーバーライドします。
第一引数はクリックされたヘッダーのPreferenceActivity.Headerインスタンス、第二引数はクリックされたポジションとなります。
@Override public void onHeaderClick(Header header, int position) { super.onHeaderClick(header, position); Log.d(TAG, "onHeaderClick: " + position); Log.d(TAG, "onHeaderClick: " + header.fragment); }
まとめ
今回はPreferenceActivityを使った近代的な設定画面の実装方法に必要なメソッドについて説明しました。public class MyPreference1Activity extends PreferenceActivity { private static final String TAG = "MyPreference1Activity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public boolean onIsMultiPane() { int orientation = getResources().getConfiguration().orientation; return orientation == Configuration.ORIENTATION_LANDSCAPE; } @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } @Override protected boolean isValidFragment(String fragmentName) { return Prefs1Fragment.class.getName().equals(fragmentName) || Prefs2Fragment.class.getName().equals(fragmentName); } @Override public void onHeaderClick(Header header, int position) { super.onHeaderClick(header, position); Log.d(TAG, "onHeaderClick: " + position); Log.d(TAG, "onHeaderClick: " + header.fragment); } public static class Prefs1Fragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_general); } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { ((MyPreference1Activity)getActivity()).finishPreferencePanel(this,100,new Intent()); return super.onPreferenceTreeClick(preferenceScreen, preference); } } public static class Prefs2Fragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle arguments = getArguments(); addPreferencesFromResource(R.xml.pref_data_sync); } } }