編輯:Android開發實例
本篇文章主要內容來自於Android Doc,我翻譯之後又做了些加工,英文好的朋友也可以直接去讀原文。
http://developer.android.com/guide/topics/ui/actionbar.html
Action Bar是一種新増的導航欄功能,在Android 3.0之後加入到系統的API當中,它標識了用戶當前操作界面的位置,並提供了額外的用戶動作、界面導航等功能。使用ActionBar的好處是,它可以給提供一種全局統一的UI界面,使得用戶在使用任何一款軟件時都懂得該如何操作,並且ActionBar還可以自動適應各種不同大小的屏幕。下面是一張使用ActionBar的界面截圖:
其中,[1]是ActionBar的圖標,[2]是兩個action按鈕,[3]是overflow按鈕。
由於Action Bar是在3.0以後的版本中加入的,如果想在2.x的版本裡使用ActionBar的話則需要引入Support Library,不過3.0之前版本的市場占有率已經非常小了,這裡簡單起見我們就不再考慮去做向下兼容,而是只考慮4.0以上版本的用法。
ActionBar的添加非常簡單,只需要在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子類就可以了,而使用Eclipse創建的項目自動就會將Application的theme指定成Theme.Holo,所以ActionBar默認都是顯示出來的。新建一個空項目並運行,效果如下圖所示:
而如果想要移除ActionBar的話通常有兩種方式,一是將theme指定成Theme.Holo.NoActionBar,表示使用一個不包含ActionBar的主題,二是在Activity中調用以下方法:
ActionBar actionBar = getActionBar(); actionBar.hide();
現在重新運行一下程序,就可以看到ActionBar不再顯示了,如下圖所示:
現在重新運行一下程序,效果如下圖所示:
- <activity
- android:name="com.example.actionbartest.MainActivity"
- android:logo="@drawable/weather" >
- </activity>
現在重新運行一下程序,結果如下圖所示:
- <activity
- android:name="com.example.actionbartest.MainActivity"
- android:label="天氣"
- android:logo="@drawable/weather" >
- </activity>
可以看到,這裡我們通過三個<item>標簽定義了三個Action按鈕。<item>標簽中又有一些屬性,其中id是該Action按鈕的唯一標識符,icon用於指定該按鈕的圖標,title用於指定該按鈕可能顯示的文字(在圖標能顯示的情況下,通常不會顯示文字),showAsAction則指定了該按鈕顯示的位置,主要有以下幾種值可選:always表示永遠顯示在ActionBar中,如果屏幕空間不夠則無法顯示,ifRoom表示屏幕空間夠的情況下顯示在ActionBar中,不夠的話就顯示在overflow中,never則表示永遠顯示在overflow中。 接著,重寫Activity的onCreateOptionsMenu()方法,代碼如下所示:
- <menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:context="com.example.actionbartest.MainActivity" >
- <item
- android:id="@+id/action_compose"
- android:icon="@drawable/ic_action_compose"
- android:showAsAction="always"
- android:title="@string/action_compose"/>
- <item
- android:id="@+id/action_delete"
- android:icon="@drawable/ic_action_delete"
- android:showAsAction="always"
- android:title="@string/action_delete"/>
- <item
- android:id="@+id/action_settings"
- android:icon="@drawable/ic_launcher"
- android:showAsAction="never"
- android:title="@string/action_settings"/>
- </menu>
這部分代碼很簡單,僅僅是調用了MenuInflater的inflate()方法來加載menu資源就可以了。現在重新運行一下程序,結果如下圖所示:
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return super.onCreateOptionsMenu(menu);
- }
可以看到,我們讓每個Action按鈕被點擊的時候都彈出一個Toast,現在重新運行一下代碼,結果如下圖所示:
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_compose:
- Toast.makeText(this, "Compose", Toast.LENGTH_SHORT).show();
- return true;
- case R.id.action_delete:
- Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
- return true;
- case R.id.action_settings:
- Toast.makeText(this, "Settings", Toast.LENGTH_SHORT).show();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
現在重新運行一下程序,結果如下圖所示:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTitle("天氣");
- setContentView(R.layout.activity_main);
- ActionBar actionBar = getActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
當點擊ActionBar圖標的時候,系統同樣會調用onOptionsItemSelected()方法,並且此時的itemId是android.R.id.home,所以finish()方法也就是加在這裡的了。 現在看上去,ActionBar導航和Back鍵的功能貌似是一樣的。沒錯,如果我們只是簡單地finish了一下,ActionBar導航和Back鍵的功能是完全一樣的,但ActionBar導航的設計初衷並不是這樣的,它和Back鍵的功能還是有一些區別的,舉個例子吧。
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- ……
- }
- }
第二步需要在AndroidManifest.xml中配置父Activity,如下所示:
- <activity
- android:name="com.example.actionbartest.MainActivity"
- android:logo="@drawable/weather" >
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="com.example.actionbartest.LaunchActivity" />
- </activity>
可以看到,這裡通過meta-data標簽指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本之後,也可以直接使用android:parentActivityName這個屬性來進行指定,如下所示:
- <activity
- android:name="com.example.actionbartest.MainActivity"
- android:logo="@drawable/weather"
- android:parentActivityName="com.example.actionbartest.LaunchActivity" >
- </activity>
第三步則需要對android.R.id.home這個事件進行一些特殊處理,如下所示:
其中,調用NavUtils.getParentActivityIntent()方法可以獲取到跳轉至父Activity的Intent,然後如果父Activity和當前Activity是在同一個Task中的,則直接調用navigateUpTo()方法進行跳轉,如果不是在同一個Task中的,則需要借助TaskStackBuilder來創建一個新的Task。 這樣,就按照標准的規范成功實現ActionBar導航的功能了。
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- Intent upIntent = NavUtils.getParentActivityIntent(this);
- if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
- TaskStackBuilder.create(this)
- .addNextIntentWithParentStack(upIntent)
- .startActivities();
- } else {
- upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- NavUtils.navigateUpTo(this, upIntent);
- }
- return true;
- ......
- }
- }
注意在showAsAction屬性中我們還聲明了一個collapseActionView,這個值表示該控件可以被合並成一個Action按鈕。 現在重新運行一下程序,效果如下圖所示:
- <menu xmlns:android="http://schemas.android.com/apk/res/android" >
- <item
- android:id="@+id/action_search"
- android:icon="@drawable/ic_action_search"
- android:actionViewClass="android.widget.SearchView"
- android:showAsAction="ifRoom|collapseActionView"
- android:title="@string/action_search" />
- ......
- </menu>
在得到了SearchView的實例之後,就可以任意地配置它的各種屬性了。關於SearchView的更多詳細用法,可以參考官方文檔 http://developer.android.com/guide/topics/search/search-dialog.html 。 除此之外,有些程序可能還希望在ActionView展開和合並的時候顯示不同的界面,其實我們只需要去注冊一個ActionView的監聽器就能實現這樣的功能了,代碼如下所示:
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- MenuItem searchItem = menu.findItem(R.id.action_search);
- SearchView searchView = (SearchView) searchItem.getActionView();
- // 配置SearchView的屬性
- ......
- return super.onCreateOptionsMenu(menu);
- }
可以看到,調用MenuItem的setOnActionExpandListener()方法就可以注冊一個監聽器了,當SearchView展開的時候就會回調onMenuItemActionExpand()方法,當SearchView合並的時候就會調用onMenuItemActionCollapse()方法,我們在這兩個方法中進行相應的UI操作就可以了。
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- MenuItem searchItem = menu.findItem(R.id.action_search);
- searchItem.setOnActionExpandListener(new OnActionExpandListener() {
- @Override
- public boolean onMenuItemActionExpand(MenuItem item) {
- Log.d("TAG", "on expand");
- return true;
- }
- @Override
- public boolean onMenuItemActionCollapse(MenuItem item) {
- Log.d("TAG", "on collapse");
- return true;
- }
- });
- return super.onCreateOptionsMenu(menu);
- }
這裡我們在onCreate()方法的最後調用了setOverflowShowingAlways()方法,而這個方法的內部就是使用反射的方式將sHasPermanentMenuKey的值設置成false,現在重新運行一下代碼,結果如下圖所示:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- ......
- setOverflowShowingAlways();
- }
- private void setOverflowShowingAlways() {
- try {
- ViewConfiguration config = ViewConfiguration.get(this);
- Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
- menuKeyField.setAccessible(true);
- menuKeyField.setBoolean(config, false);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
可以看到,這裡我們重寫了一個onMenuOpened()方法,當overflow被展開的時候就會回調這個方法,接著在這個方法的內部通過返回反射的方法將MenuBuilder的setOptionalIconsVisible變量設置為true就可以了。 現在重新運行一下代碼,結果如下圖所示:
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
- if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
- try {
- Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
- m.setAccessible(true);
- m.invoke(menu, true);
- } catch (Exception e) {
- }
- }
- }
- return super.onMenuOpened(featureId, menu);
- }
今天開始模仿開發者頭條的側滑菜單,是本系列第二篇文章,相信大家已經看到很多app使用這種側滑。今天我來教大家用Android自帶DrawerLayo
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
知識點: 這次將繼續上一篇文章沒有講完的Menu的學習,上下文菜單(Context menu)和彈出菜單(Popup menu)。 上下文菜單 上下文菜單提供對U