-
Notifications
You must be signed in to change notification settings - Fork 354
2.05. ActionBarとインタラクション制御
この章では、Honeycomb 以降に導入された Android 標準の UI コンポーネントである ActionBar と、インタラクション制御について解説します。
参考:UI デザインとしてのAction Bar | Android Developers
参考:プログラミングとしてのAction Bar | Android Developers
- ActionBar - [ActionBar の基本](#ActionBar の基本) - NavigationMode - ActionItem - [App Icon Navigation](#App Icon Navigation) - [Split ActionBar](#Split ActionBar) - ActionView - ActionBarSherlock
- インタラクション制御 - [Activity や Fragment のコールバックメソッド](#Activity や Fragment のコールバックメソッド) - [View の状態を監視する方法](#View の状態を監視する方法)
Android の公式な UI デザインの中でも、特に重要な役割をもっているものが ActionBar です。
ユーザを適切にナビゲーションし、アプリの中での目的を達成するには、ActionBar の知識と実装は必須のものとなっています。
ActionBar とは、アプリにある複数の画面で恒久的に表示される、主にナビゲーションと適切なアクションの提示のために利用される、重要な UI コンポーネントです。
ActionBar には、以下の 4 つのコンポーネントがあります。
- App Icon
- アプリのアイコンです。単なるアイコンとしての機能だけでなく、ホームに戻る、や、階層を 1 つ戻る、などの役割を持つこともできます。
- View Control
- 異なる View に様々なデータを表示するような場合に、ユーザが素早く View を切り替えるためのコンポーネントです。右下に三角形のマークが付いているものは、ドロップダウンリストのメニューが表示されます。これ以外に、タブによる切り替えも用意されています。
- ActionItem Buttons(Action Buttons)
- ここに配置されるボタン類は、アプリやその画面のなかで最も重要なアクションを促すために配置されます。画面幅などでこのエリア内に収まらないボタンは、自動的に、4 の Action Overflow に移されます。Action Buttons は、ActionBar を分割し、Action Buttons を画面下部に表示させることもできます。
- Action Overflow
- 画面に収まらなかったり、意図的に Action Overflow に入るよう設定した Action Buttons がここにまとめられます。ここに収める Action Buttons は優先順位の低いものとして位置づけられます。
また、ActionBar を導入するにあたって、以下に上げる重要な要素があります。
ActionBar には、3 つのナビゲーションモードが用意されています。 1 つの Activity で選択できるモードは、このうち 1 つだけです。
デフォルトのナビゲーションモードです。
ドロップダウンのリストから、項目を 1 つ選択してコンテンツを切り替えるタイプのナビゲーションモードです。
// Honeycomb 以降向けのコード
public class SherlockListNavigationActivity extends Activity implements OnNavigationListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
// List Navigation のリストに表示するもの
List<String> list = new ArrayList<String>();
list.add("Navi Menu 1");
list.add("Navi Menu 2");
list.add("Navi Menu 3");
// ナビゲーションモードを List Navigation に設定
getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
// List Navigation の準備
// ArrayAdapter は一覧表示のための、データと View をひもづけるためのクラス。詳細は別の章。
getActionBar().setListNavigationCallbacks(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
android.R.id.text1, list),
this);
// タイトルを表示しないようにする
getActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
}
// List Navigation の一覧から項目を選択したら呼び出されるコールバック
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
// ここで、どの項目が選択されたかを検知し、適切なイベント処理を行う
// イベント処理が実行されたら、true を返すようにする
return false;
}
}
複数のタブから 1 つを選択してコンテンツを切り替えるタイプのナビゲーションモードです。
タブの位置は、画面の大きさによって決定されます。
横幅の狭い画面では、アクションバーの直下に表示されますが、広い画面では、アクションバーのタイトル部分の右横にタブが統合されます。
これは、端末の画面回転時にも判定が行われるため、縦画面と横画面で動的にアクションバーのレイアウトが切り替わることになります。
// Honeycomb 以降向けのコード
public class SherlockTabNavigationActivity extends Activity implements TabListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
// タブナビゲーションモードに設定
getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// タブを作成して追加。タブの選択・解除・再選択をハンドリングするコールバックの TabListener をセットしないと実行時例外でクラッシュする
getActionBar().addTab(getSupportActionBar().newTab().setText("Tab1").setTabListener(this));
getActionBar().addTab(getSupportActionBar().newTab().setText("Tab2").setTabListener(this));
getActionBar().addTab(getSupportActionBar().newTab().setText("Tab3").setTabListener(this));
}
// タブナビゲーションの Tab が選択された時のコールバック
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
}
// タブナビゲーションの Tab が選択解除された時のコールバック
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
// タブナビゲーションの Tab が再度選択された時のコールバック
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
これまでの OptionsMenu(メニューキーを押して表示するメニュー)の代替として、アクションバーに含められるメニューです。
リソースは全て OptionsMenu のものを流用することが可能ですが、一部属性がアクションバー向けに追加されています。
android:showAsAction
-
アクションバーへの出し方を決定するための属性です。
値 意味 always 常に表示します。最も重要度の高いメニューとして扱います。 ifRoom 他の ActionBar のコンポーネントが占める領域を見て、空きがあれば表示します。 never 常に ActionBar 上には表示せず、その他のメニュー(3 つの点のアイコン)の中にまとめられます。最も重要度が引くい項目に適用します。 withText 横幅の広い画面において、アイコンだけでなく、文言も一緒に表示するオプションです。
always
、ifRoom
、never
は一緒に指定することができません。必ずこの 3 つのどれかを選択します。
ifRoom
指定して画面に入りきらなかったものと、never
指定したものは、下記のように Overflow にまとめられます。
また、アイコンを設定せず、ラベルのみを設定した場合で、Action Item に並べられるときは、全て大文字になって表示されます。
端末の画面サイズに応じて、ActionBar が自動で Action Item の表示をハンドリングしてくれます。
タブレット型のような大きなディスプレイでは、アイコンとラベルが同時に表示されますが、モバイル向けの端末では、横幅によってアイコンのみの場合と、ラベルとアイコンが同時に表示される場合とがあります。
横画面にしても、横幅が 480dp に満たない端末では、常にどちらかだけになります。
標準で、アクションバーの左端には、アプリのアイコンが表示されています。
このアイコンを、ナビゲーションのための UI として機能させることができます。
Android の流儀としての使い方として、下記の 2 つが想定されています。
- アプリのホーム画面(アプリの起動直後の画面)へ戻る、ホームボタンの役割
- アプリのナビゲーションの階層構造を上に戻る、戻るボタンの役割
この 2 つの違いは、アイコンの表示にも影響します。
左が、ホームボタンとしての役割の時、右が、戻るボタンとしての役割の時の表示です。
戻るボタンとして機能させるときには、左向きの矢印が表示されます。
アイコンがタップされた時の制御については、後述するインタラクション制御で説明します。
Action Item を、画面上部の ActionBar から切り離し、画面下部に 1 列に表示するモードです。
AndroidManifest において、<activity>
の属性として、android:uiOptions
にsplitActionBarWhenNarrow
を設定することで実現出来ます。
ActionBar は Android 3.x で導入された新しい UI コンポーネントです。Android 4.x以降は、タブレットもモバイル端末も同じ OS で動かすことを標準に据えているので、Android 2.x でも ActionBar の導入が進んでいます。
一方、Google が公式にリリースしている Support Package には、Android 2.x でこのコンポーネントを使用出来るようにするものは含まれていません。よって、サードパーティ製のライブラリで、Android 2.x でも ActionBar を使えるようにします。
現在最も利用されているサードパーティ製ライブラリは、ActionBarSherlock です。
Android が標準で用意している API と異なる部分は以下のとおりです。
- 画面コンポーネントを ActionBarSherlock のものに置き換える
- SherlockActivity、SherlockFragmentActivity など
- 標準 API と同じ名前のクラスで、ActionBarSherlock の名前空間にあるクラスに置き換える
- Menu など
- テーマを、ActionBarSherlock のものに置き換える
- Theme.Sherlock、Theme.Sherlock.Light など
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.mixi.sample.actionbar.sherlock"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Sherlock">
<!-- ActionBarSherlock の theme を使用するようにする -->
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Split ActionBar を実現するための属性指定 -->
<activity
android:name=".SherlockListNavigationActivity"
android:label="@string/app_name"
android:uiOptions="splitActionBarWhenNarrow">
</activity>
<activity
android:name=".SherlockTabNavigationActivity"
android:label="@string/app_name">
</activity>
<activity
android:name=".SherlockStandardNavigationActivity"
android:label="@string/app_name">
</activity>
</application>
</manifest>
package jp.mixi.sample.actionbar.sherlock;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import java.util.ArrayList;
import java.util.List;
public class SherlockListNavigationActivity extends SherlockActivity implements OnNavigationListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
// List Navigation のリストに表示するもの
List<String> list = new ArrayList<String>();
list.add("Navi Menu 1");
list.add("Navi Menu 2");
list.add("Navi Menu 3");
// ナビゲーションモードを List Navigation に設定
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
// List Navigation の準備
getSupportActionBar().setListNavigationCallbacks(
new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.simple_list_item_1,
android.R.id.text1, list),
this);
// タイトルを表示しないようにする
getSupportActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// Menu が Android 標準 API のものとは違うので、区別するために getSupportMenuInflater() を呼ぶ
getSupportMenuInflater().inflate(R.menu.main, menu);
return true;
}
// List Navigation の一覧から項目を選択したら呼び出されるコールバック
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
return false;
}
}
Android Action Bar Style Generator などで、簡単に Drawable Resource や Style Resource を生成できるようになっています。
以下のように、Style Resource として各種 Drawable を利用してカスタマイズしていきます。
<resources>
<!-- アクションバー の各種スタイルの設定をまとめた、テーマスタイル -->
<style name="Theme.Example" parent="@style/Theme.Sherlock.Light">
<!-- アクションバーの背景 Drawable -->
<item name="actionBarItemBackground">@drawable/selectable_background_example</item>
<!-- ポップアップで表示されるメニュー項目の Style -->
<item name="popupMenuStyle">@style/PopupMenu.Example</item>
<item name="dropDownListViewStyle">@style/DropDownListView.Example</item>
<item name="actionBarTabStyle">@style/ActionBarTabStyle.Example</item>
<item name="actionDropDownStyle">@style/DropDownNav.Example</item>
<item name="actionBarStyle">@style/ActionBar.Solid.Example</item>
<item name="actionModeBackground">@drawable/cab_background_top_example</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_example</item>
<item name="actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Example</item>
</style>
<style name="ActionBar.Solid.Example" parent="@style/Widget.Sherlock.Light.ActionBar.Solid">
<item name="background">@drawable/ab_solid_example</item>
<item name="backgroundStacked">@drawable/ab_stacked_solid_example</item>
<item name="backgroundSplit">@drawable/ab_bottom_solid_example</item>
<item name="progressBarStyle">@style/ProgressBar.Example</item>
</style>
<style name="ActionBar.Transparent.Example" parent="@style/Widget.Sherlock.Light.ActionBar">
<item name="background">@drawable/ab_transparent_example</item>
<item name="progressBarStyle">@style/ProgressBar.Example</item>
</style>
<style name="PopupMenu.Example" parent="@style/Widget.Sherlock.Light.ListPopupWindow">
<item name="android:popupBackground">@drawable/menu_dropdown_panel_example</item>
</style>
<style name="DropDownListView.Example" parent="@style/Widget.Sherlock.Light.ListView.DropDown">
<item name="android:listSelector">@drawable/selectable_background_example</item>
</style>
<style name="ActionBarTabStyle.Example" parent="@style/Widget.Sherlock.Light.ActionBar.TabView">
<item name="android:background">@drawable/tab_indicator_ab_example</item>
</style>
<style name="DropDownNav.Example" parent="@style/Widget.Sherlock.Light.Spinner.DropDown.ActionBar">
<item name="android:background">@drawable/spinner_background_ab_example</item>
<item name="android:popupBackground">@drawable/menu_dropdown_panel_example</item>
<item name="android:dropDownSelector">@drawable/selectable_background_example</item>
</style>
<style name="ProgressBar.Example" parent="@style/Widget.Sherlock.Light.ProgressBar.Horizontal">
<item name="android:progressDrawable">@drawable/progress_horizontal_example</item>
</style>
<style name="ActionButton.CloseMode.Example" parent="@style/Widget.Sherlock.Light.ActionButton.CloseMode">
<item name="android:background">@drawable/btn_cab_done_example</item>
</style>
<!-- this style is only referenced in a Light.DarkActionBar based theme -->
<style name="Theme.Example.Widget" parent="@style/Theme.Sherlock">
<item name="popupMenuStyle">@style/PopupMenu.Example</item>
<item name="dropDownListViewStyle">@style/DropDownListView.Example</item>
</style>
</resources>
Activity と Fragment には、メニューの構成と表示について、下記のような 2 種類のメニューを扱うコールバックメソッドが用意されています。
メニューキーで表示されるメニュー、また ActionBar に表示される ActionItem の構成を扱います。
下記のコールバックメソッドが用意されています。
メソッド名 | 意味 |
---|---|
onPrepareOptionsMenu | OptionsMenu を表示する前に、メニュー要素の状態を管理するために呼び出される |
onCreateOptionsMenu | OptionsMenu の構成を初期化するために、Activity や Fragment のライフサイクルの中で 1 度だけ呼ばれる |
onOptionsItemSelected | OptionsMenu の選択状況を見て、適切なアクションを起こすために呼び出される |
public class MainActivity extends Activity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// ここで、状態に応じてメニューの有効・無効を切り替えたりなどの処理をする
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// ここで、この Activity で利用するメニューのリソースを読み込む
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 選択されたメニューに対応するイベント処理をここで実行する
return super.onOptionsItemSelected(item);
}
}
View の長押しで表示されるメニューの構成を扱います。
下記のコールバックメソッドが用意されています。
メソッド名 | 意味 |
---|---|
onCreateContextMenu | ContextMenu の構成を初期化する |
onContextItemSelected | ContextMenu の選択状況を見て、適切なアクションを起こすために呼び出される |
public class MainActivity extends Activity {
@Override
protected void onStart() {
super.onStart();
// View に長押しメニュー用のコールバックを設定する
// 実際には、View に OnCreateContextMenuListener を設定するだけ
// 登録処理を Activity が肩代わりしている
View helloWorld = findViewById(R.id.HelloWorld);
registerForContextMenu(helloWorld);
}
@Override
protected void onStop() {
// View に設定した長押しメニュー用のコールバックを解除する
View helloWorld = findViewById(R.id.HelloWorld);
unregisterForContextMenu(helloWorld);
super.onStop();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
// ここで、長押しメニューで利用するメニューリソースを読み込む
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// ここで、選択されたメニューリソースに対応するイベント処理を実行する
return super.onContextItemSelected(item);
}
}
View には、以下のような「状態(State)」が定義されています。
View の種類によって、取り得る状態は様々です。
状態名 | 意味 |
---|---|
normal | 何もしていない |
enabled | View がユーザ操作を受け付ける状態 |
focused | View がユーザ操作によってフォーカスを持っている状態 |
selected | View がユーザ操作によって選択されている状態 |
checked | View がユーザ操作によってチェックされている状態 |
pressed | View がユーザ操作によって押されている(クリックされている・タップされている)状態 |
これらそれぞれの状態について、Observer パターンでイベントを監視するための仕組みが用意されています。
監視するためのオブジェクトの登録方法によっては、Activity のライフサイクルに合わせて監視オブジェクトの管理を剃る必要のあるものがあることに注意してください。
View をタップした時に呼び出されるイベントを拾うための Observer です。
View を長押しした時に呼び出されるイベントを拾うための Observer です。
View のフォーカスが移動した時のイベントを拾うための Observer です。
CheckBox などで、チェック状態が変化した時のイベントを拾うための Observer です。
EditText などで、入力テキストが変更された時のイベントを拾うための Observer です。 こちらは、Activity や Fragment のライフサイクルに合わせて、適宜 View への登録と解除を行う必要があります。
- (実習) 実習用プロジェクトが、libraries/ActionBarSherlock を参照するように設定してください
- (実習) 1. で設定したプロジェクトで、ActionBar の TabNavigation を実現し、3 つのタブを持つ画面を作成してください
- (実習) TabNavigation で、タブを選択された時に、どのタブが選択されたかを
Toast
で表示するようにしてください - (課題)
- (課題)
- (実習) OptionsMenu に、以下の 3 つの項目を表示し、それぞれ選択時に、どのメニューが選択されたかを
Toast
で表示するようにしてください - (実習) ActionBarSherlock を参照する実習用プロジェクトで OptionsMenu を扱った場合の、OptionsMenu の表示のされ方の違いを、エミュレータを用いて、画面の大きさを元に考察してレポートに記述してください
- (課題)
- (課題)
Portions of this page are reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.