はじめに
前回は、順最寄り駅の一覧を表示するFragmentを追加して、タブレット向けの2ペイン表示する方法を解説しました。第9回目の本稿では、スマートフォン向けの1ペイン画面を追加して、両方の環境に対応できるように修正してみます。
対象読者
Androidアプリケーションの開発を始めたい方で、JavaとEclipseの基本的な知識がある方を対象とします。
スクリーンサイズによるレイアウト切り替え
2ペイン表示か1ペイン表示かは、端末のスクリーンサイズをもとに判断します。Android 3.2より前では、APIを用いてスクリーンサイズを取得して、レイアウトを切り替える方法しかありませんでした。
Android 3.2以降では、画像リソースと同様、端末の解像度別にフォルダを分けておけば、自動的に最適なレイアウトファイルが選択されるようになりました。コードによる判断が必要でなければ、この方法での判別がシンプルでしょう。
フォルダの規則
プロジェクト内のresフォルダ以下に、リソースを示す文字列と特定の識別子を付加した名前のフォルダを作成しておけば、その定義ファイルが自動的に読み込まれます。次の表に、解像度に関する規則をまとめています。
付加する識別子 | 意味 |
---|---|
sw<N>dp | 指定した幅(Ndp)以上の場合に選択される(smallestWidth) |
w<N>dp | 指定した幅(Ndp)が可能な場合に選択される(Available width) |
h<N>dp | 指定した高さ(Ndp)が可能な場合に選択される(Available height) |
port | 縦向きの場合に選択される |
land | 横向きの場合に選択される |
識別子は、-(ハイフン)で区切って複数指定することもできます。例えば、レイアウトファイルの場合、レイアウトを示すlayoutにsw600dpを付加して、「layout-sw600dp」とすれば横幅が600ドット以上の端末の場合、「layout-h1024dp-port」なら、高さが1024ドット以上の端末で、縦向き表示のときに参照されるようになります。
なお規則についての詳細は、Android Developersサイトを参照してください。
一般的には、横幅のスクリーンサイズが600dpなら7インチクラス、720dpなら10インチクラスのタブレット端末になります。
今回のアプリのレイアウトでは、7インチクラスでも縦向きの2ペイン表示は見づらいので、次のような3つのフォルダ構成にします。
識別子 | 端末 | ペイン数 |
---|---|---|
sw600dp-land | 横幅が600~720ドット未満で横向きのとき | 2ペイン |
sw720dp | 横幅が720ドット以上のとき | 2ペイン |
指定なし | 上記以外のとき | 1ペイン |
従って、layout-sw600dp-land、layout-sw720dp、layoutという3つのフォルダに、同じ名前でレイアウトファイルを作成しておけば、自動的に選択されて読み込まれるようになります。なお、layout-sw600dp-landとlayout-sw720dpフォルダには、まったく同じレイアウトファイルをコピーする形になります。
リソースのエイリアス機能
前述のように、layout-sw600dp-landとlayout-sw720dpフォルダには、同じものが複数存在しています。2つくらいであればいいのでしょうが、ファイルの修正時に漏れが発生する可能性もありますので、できればファイルの重複は避けたいところです。
そのような場合には、リソースのエイリアス機能を利用します。エイリアスは、リソースファイルのショートカットやリンクファイルのようなものです。
今回は、layoutフォルダのみに実際のレイアウトファイルを定義し、その他のフォルダには、エイリアスのファイルを作成することにします。
まず、1ペインと2ペインのレイアウトを、layoutフォルダ以下に、onepane.xml、twopanes.xmlという名前で作成します。onepane.xmlの内容は、activity_main.xmlと同じにしておきます。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <fragment android:id="@+id/eki_list" android:name="com.rakuraku.android.ekimap.EkiListFragment" android:layout_height="fill_parent" android:layout_width="200dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/map" android:name="com.rakuraku.android.ekimap.MyMapFragment" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout >
次にエイリアスファイルを、前述の場合分けに従って3つ作成します。ただし、エイリアスの場合は、layoutフォルダではなく、valuesというフォルダになります。
なおサンプルでは、エイリアスのファイル名は、layouts.xmlにしています。
<resources> <item name="main_layout" type="layout">@layout/onepane</item> </resources>
このようにすると、main_layoutという名前で、layoutフォルダのonepane.xmlのエイリアスを定義したことになります。また、Activity内で実行するsetContentViewメソッドでは、R.layout.main_layoutという引数を指定します。
なお、values-sw600dp-landと、values-sw720dpには、2ペインのエイリアスを定義します。
<resources> <item name="main_layout" type="layout">@layout/twopanes</item> </resources>
最終的に、レイアウトファイルは、次のようなファイル構成です。
res ┬ layout ──────┬ onepane.xml │ └ twopanes.xml ├ values ─────── layouts.xml ├ values-sw600dp-land ─ layouts.xml └ values-sw720dp ─── layouts.xml