このレッスンでは、古いデバイスをサポートしつつ新しい API を反映する実装を作成する方法について説明します。
代替ソリューションを決定する
下位互換性を維持しつつ新しい UI 機能を使用する場合の最も困難なタスクは、古いプラットフォーム バージョン用の古い(代替)ソリューションを決定して実装することです。多くの場合は、古い UI フレームワーク機能により、新しい UI コンポーネントの目的を達成できます。次に例を示します。
-
アクションバーは、カスタム タイトルバーまたはアクティビティ レイアウトのビューとして、画像ボタンを含む水平
LinearLayout
を使用することで実装できます。オーバーフロー アクションは、デバイスのメニューボタンの下に表示できます。 -
アクションバー タブは、ボタンを含む水平
LinearLayout
か、TabWidget
UI 要素を使用して実装できます。 -
NumberPicker
ウィジェットとSwitch
ウィジェットは、それぞれSpinner
ウィジェットとToggleButton
ウィジェットを使用して実装できます。 -
ListPopupWindow
ウィジェットとPopupMenu
ウィジェットはPopupWindow
ウィジェットを使用して実装できます。
一般的に、新しい UI コンポーネントを古いデバイスにバックポートするための万能なソリューションはありません。ユーザー エクスペリエンスに注意する必要があります。古いデバイスのユーザーは、新しいデザイン パターンと UI コンポーネントに馴染めない可能性があります。どうすればユーザーが使い慣れた要素で同じ機能を実現できるかを考えましょう。アプリのエコシステム(アクションバーなど)で新しい UI コンポーネントが目立っていたり、対話モデルが非常にシンプルで直感的であったりすれば(ViewPager
を使用したビューのスワイプなど)、多くの場合、それほど問題は生じません。
古い API を使用するタブを実装する
アクションバー タブの古い実装を作成するには、TabWidget
と TabHost
を使用できます(代わりに、水平方向に置かれた Button
ウィジェットも使用できます)。これは、TabHelperEclair
および CompatTabEclair
という名前のクラスに実装します。この実装では、Android 2.0(Eclair)より前に導入された API を使用するからです。

図 1. タブの Eclair 実装のクラスの図
CompatTabEclair
実装は、タブテキストやアイコンなどのタブプロパティをインスタンス変数に格納します。これは、このストレージの処理に使用できる ActionBar.Tab
オブジェクトがないためです。
class CompatTabEclair internal constructor(val activity: FragmentActivity, tag: String) :
CompatTab(tag) {
// Store these properties in the instance,
// as there is no ActionBar.Tab object.
private var text: CharSequence? = null
...
override fun setText(resId: Int): CompatTab {
// Our older implementation simply stores this
// information in the object instance.
text = activity.resources.getText(resId)
return this
}
...
// Do the same for other properties (icon, callback, etc.)
}
public class CompatTabEclair extends CompatTab {
// Store these properties in the instance,
// as there is no ActionBar.Tab object.
private CharSequence text;
...
public CompatTab setText(int resId) {
// Our older implementation simply stores this
// information in the object instance.
text = activity.getResources().getText(resId);
return this;
}
...
// Do the same for other properties (icon, callback, etc.)
}
TabHelperEclair
の実装では、TabHost
ウィジェットのメソッドを使用して、TabHost.TabSpec
オブジェクトとタブ インジケーターを作成します。
class TabHelperEclair internal constructor(activity: FragmentActivity) : TabHelper(activity) {
private var tabHost: TabHost? = null
...
override fun setUp() {
// Our activity layout for pre-Honeycomb devices
// must contain a TabHost.
tabHost = tabHost ?: mActivity.findViewById<TabHost>(android.R.id.tabhost).apply {
setup()
}
}
override fun addTab(tab: CompatTab) {
...
tabHost?.newTabSpec(tab.tag)?.run {
setIndicator(tab.getText()) // And optional icon
...
tabHost?.addTab(this)
}
}
// The other important method, newTab() is part of
// the base implementation.
}
public class TabHelperEclair extends TabHelper {
private TabHost tabHost;
...
protected void setUp() {
if (tabHost == null) {
// Our activity layout for pre-Honeycomb devices
// must contain a TabHost.
tabHost = (TabHost) mActivity.findViewById(
android.R.id.tabhost);
tabHost.setup();
}
}
public void addTab(CompatTab tab) {
...
TabSpec spec = tabHost
.newTabSpec(tag)
.setIndicator(tab.getText()); // And optional icon
...
tabHost.addTab(spec);
}
// The other important method, newTab() is part of
// the base implementation.
}
これで、CompatTab
と TabHelper
の 2 つの実装を用意できました。1 つは Android 3.0 以降を実行するデバイスで動作し、新しい API を使用します。もう 1 つは Android 2.0 以降を実行するデバイスで動作し、古い API を使用します。次のレッスンでは、これらの実装をアプリで使用する方法について説明します。