Android軒轅劍之ActionBar之三

傳送門 ☞ 輪子的專欄 ☞ 轉載請註明 ☞ http://blog.csdn.net/leverage_1229

6添加Action Provider

        與action view類似,Action Provider(由ActionProvider類定義的)用一個定製的佈局代替一個action item,它還需要對所有這些item行爲的控制。當你在action bar中給一個菜單項聲明一個action item時,它不僅要一個定製的佈局來控制這個菜單項的外觀,而且當它顯示在溢出菜單中時,還要處理它的默認事件。無論是在action bar中還是在溢出菜單中,它都能夠提供一個子菜單。
        例如,ActionProvider的擴展類ShareActionProvider,它通過在action bar中顯示一個有效的共享目標列表來方便共享操作。與使用傳統的調用ACTION_SEND類型Intent對象的action item不同,你能夠聲明一個ShareActionProvider對象來處理一個action item。這種action provider會保留一個帶有處理ACTION_SEND類型Intent對象的應用程序的下拉列表,即使這個菜單項顯示在溢出菜單中。所以當你使用像這樣的Action Provider時,你不必處理有關這個菜單項的用戶事件。
        要給一個操作項聲明一個操作提供器,就要在菜單資源中對應的<item>元素中定義android:actionProviderClass屬性,提供器要使用完整的類名。
<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/menu_share"

          android:title="@string/share"

          android:showAsAction="ifRoom"

          android:actionProviderClass="android.widget.ShareActionProvider" />

    ...

</menu>
        在這個例子中,用ShareActionProvider類作爲action provider,在這裏,action provider需要菜單項的控制,並處理它們在action bar中的外觀和行爲以及在溢出菜單中的行爲。你必須依然給這個菜單項提供一個用於溢出菜單的文本標題。
        儘管action provider提供了它在溢出菜單中顯示時所能執行的默認操作,但是Activity(或Fragment)也能夠通過處理來自onOptionsItemSelected()回調方法的點擊事件來重寫這個默認操作。如果你不在這個回調方法中處理點擊事件,那麼action provider會接收onPerformDefaultAction()回調來處理事件。但是,如果action provider提供了一個子菜單,那麼Activity將不會接收onOptionsItemSelected()回調,因爲子菜單的顯示替代了選擇時調用的默認菜單行爲。

6.1使用ShareActionProvider類

        如果你想要在action bar中提供一個“共享”操作,以充分利用安裝在設備上的其他應用程序(如,把一張圖片共享給短短信或社交應用程序使用),那麼使用ShareActionProvider類是一個有效的方法,而不是添加一個調用ACTION_SEND類型Intent對象的action item。當你給一個action item使用ShareActionProvider類時,它會呈現一個帶有能夠處理ACTION_SEND類型Intent對象的應用程序的下拉列表。
        創建子菜單的所有邏輯,包括共享目標的封裝、點擊事件的處理(包在溢出菜單中的項目顯示)等,都在ShareActionProvider類中實現了---你需要編寫的唯一的代碼是給對應的菜單項聲明action provider,並指定共享的Intent對象。
        默認情況,ShareActionProvider對象會基於用戶的使用頻率來保留共享目標的排列順序。使用頻率高的目標應用程序會顯示在下來列表的上面,並且最常用的目標會作爲默認共享目標直接顯示在action bar。默認情況下,排序信息被保存在由DEFAULT_SHARE_HISTORY_FILE_NAME指定名稱的私有文件中。如果你只使用一種操作類型ShareActionProvider類或它的一個子類,那麼你應該繼續使用這個默認的歷史文件,而不需要做任何事情。但是,如果你使用了不同類型的多個操作的ShareActionProvider類或它的一個子類,那麼爲了保持它們自己的歷史,每種ShareActionProvider類都應該指定它們自己的歷史文件。給每種ShareActionProvider類指定不同的歷史文件,就要調用setShareHistoryFileName()方法,並且提供一個XML文件的名字(如,custom_share_history.xml)
        注意:儘管ShareActionProvider類是基於使用頻率來排列共享目標的,但是這種行爲是可擴展的,並且ShareActionProvider類的擴展能夠基於歷史文件執行不同的行爲和排序。
        要添加ShareActionProvider對象,只需簡單的給android.actionProviderClass屬性設定android.widget.ShareActionProvider屬性值就可以了。唯一要做的事情是定義你要用於共享的Intent對象,你必須先調用getActionProvider()方法來獲取跟菜單項匹配的ShareActionProvider對象,然後調用setShareIntent()方法。
        如果對於共享的Intent對象的格式依賴於被選擇的菜單項,或其他在Activity生存週期內改變的變量,那麼你應該把ShareActionProvider對象保存在一個成員屬性裏,並在需要的時候調用setShareIntent()方法來更新它。
private ShareActionProvider mShareActionProvider;

...

@Override

public boolean onCreateOptionsMenu(Menu menu) {

    mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();

    mShareActionProvider.setShareIntent(getDefaultShareIntent());

    return true;

}
        上例中ShareActionProvider對象處理所有的跟這個菜單項有關的用戶交互,並且不需要處理來自onOptionsItemSelected()回調方法的點擊事件。

6.2創建自定義的Action Provider

        當你想要創建一個有動態行爲和在溢出菜單中有默認圖標的action view時,,繼承ActionProvider類來定義這些行爲是一個比好的的方案。創建自己的action provider,提供一個有組織的可重用的組件,而不是在Fragment或Activity的代碼中處理各種action item的變換和行爲。要創建自己的action provider,只需簡單的繼承ActionProvider類,並且實現合適的回調方法。你應該實現以下重要的回調方法:

6.2.1ActionProvider()

        這個構造器把應用程序的Context對象傳遞個操作提供器,你應該把它保存在一個成員變量中,以便其他的回調方法使用。

6.2.2OnCreateActionView()

        這是你給菜單項定義action view的地方。使用從構造器中接收的Context對象,獲取一個LayoutInflater對象的實例,並且用XML資源來填充action view,然後註冊事件監聽器。
public View onCreateActionView() {

    LayoutInflater layoutInflater = LayoutInflater.from(mContext);

    View view = layoutInflater.inflate(R.layout.action_provider, null);

    ImageButton button = (ImageButton) view.findViewById(R.id.button);

    button.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View v) {

            // Do something...

        }

    });

    return view;

}

6.2.3onPerformDefaultAction()

        在選中溢出菜單中的菜單時,系統會調用這個方法,並且action provider應該這對這個選中的菜單項執行默認的操作。但是,如果你的action provider提供了一個子菜單,即使是溢出菜單中一個菜單項的子菜單,那麼也要通過onPrepareSubMenu()回調方法來顯示子菜單。這樣onPerformDefaultAction()在子菜單顯示時就不會被調用。注意:實現了onOptionsItemSelected()回調方法的Activity或Frament對象能夠通過處理item-selected事件(並且返回true)來覆蓋action provider的默認行爲,這種情況下,系統不會調用onPerformDefaultAction()回調方法。

7添加導航標籤

        當你想要在一個Activity中提供導航標籤時,使用action bar的選項標籤是一個非常好的選擇(而不是使用TabWidget類),因爲系統會調整action bar選項標籤來適應不同尺寸的屏幕的需要---在屏幕足夠寬的時候,導航選項標籤會被放到主action bar中;當屏幕太窄的時候,選項標籤會被放到一個分離的橫條中。
        要使用選項標籤在Fragmengt之間切換,你必須在每次選擇一個選項標籤時執行一個Fragment事務處理。如果你不熟悉如何使用FragmentTransaction對象來改變Fragment,請閱讀先前Fragment章節。首先,你的佈局必須包含一個用於放置跟每個Fragment對象關聯的選項標籤的ViewGroup對象。並且要確保這個ViewGroup對象有一個資源ID,以便你能夠在選項標籤的切換代碼中能夠引用它。另外,如果選項標籤的內容填充在Activity的佈局中(不包括action bar),那麼Activity不需要任何佈局(你甚至不需要調用setContentView()方法)。相反,你能夠把每個Fragment對象放到默認的根ViewGroup對象中,你能夠用android.R.id.content ID來引用這個ViewGroup對象(在Fragment執行事務期間,你能夠在下面的示例代碼中看到如何使用這個ID的。
        決定了Fragment對象在佈局中的顯示位置後,添加選項標籤的基本過程如下:
實現ActionBar.TabListener接口。這個接口中回調方法會響應選項標籤上的用戶事件,以便你能夠切換Fragment對象;
對於每個要添加的選項標籤,都要實例化一個ActionBar.Tab對象,並且調用setTabListener()方法設置ActionBar.Tab對象的事件監聽器。還可以用setText()或setIcon()方法來設置選項標籤的標題或圖標;
通過調用addTab()方法,把每個選項標籤添加到操作欄。
        在查看ActionBar.TabListener接口時,注意到回調方法只提供了被選擇的ActionBar.Tab對象和執行Fragment事務處理的FragmentTransaction對象---沒有說明任何有關切換什麼Fragment。因此。你必須定義自己的每個ActionBar.Tab之間的關聯,以及ActionBar.Tab所代表的適合的Fragment對象(爲了執行合適的Fragment事務處理)。依賴你的設計,會有幾種不同的方法來定義這種關聯。在下面的例子中,ActionBar.TabListener接口的實現提供了一個構造器,這樣每個新的選項標籤都會使用它自己的監聽器實例。每個監聽器實例都定義了幾個在對應Fragment對象上執行事務處理時必須的幾個成員變量。例如,以下示例是ActionBar.TabListener接口的一種實現,在這個實現中,每個選項標籤都使用了它自己的監聽器實例。
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {

    private Fragment mFragment;

    private final Activity mActivity;

    private final String mTag;

    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> clz) {

        mActivity = activity;

        mTag = tag;

        mClass = clz;

    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {   

        if (mFragment == null) {

            mFragment = Fragment.instantiate(mActivity, mClass.getName());

            ft.add(android.R.id.content, mFragment, mTag);

        } else {

            ft.attach(mFragment);

        }

    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {

        if (mFragment != null) {

            ft.detach(mFragment);

        }

    }
 
    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }

}
        注意:針對每個回調中的Fragment事務處理,你都不必調用FragmentTransaction.commit()方法---系統會調用這個方法,並且如果你自己調用了這個方法,有可能會拋出一個異常。你也不能把這些Fragment事務處理添加到後臺堆棧中。在這個例子中,當對應的選項標籤被選擇時,監聽器只是簡單的把一個Fragment對象附加(attach()方法)到Activity佈局上---或者,如果沒有實例化,就會創建這個Fragment對象,並且把它添加(add()方法)到佈局中(android.R.id.content ViewGroup的一個子類),當這個選項標籤解除選擇時,對應的Fragment對象也會被解除與佈局的依附關係。
        ActionBar.TabListener的實現做了大量的工作,剩下的事情就是創建每個ActionBar.Tab對象並把它添加到ActionBar對象中,另外,你必須調用setNavigationMode(NAVIGATION_MODE_TABS)方法來讓選項標籤可見。如果選項標籤的標題實際指示了當前的View對象,你也可以通過調用setDisplayShowTitleEnabled(false)方法來禁用Activity的標題。
        例如,下面的代碼使用上面定義的監聽器在action bar中添加了兩個選項標籤。
@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    ActionBar actionBar = getActionBar();

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    actionBar.setDisplayShowTitleEnabled(false);

    Tab tab = actionBar.newTab()

            .setText(R.string.artist)

            .setTabListener(new TabListener<ArtistFragment>(

                    this, "artist", ArtistFragment.class));

    actionBar.addTab(tab);

    tab = actionBar.newTab()

        .setText(R.string.album)

        .setTabListener(new TabListener<AlbumFragment>(

                this, "album", AlbumFragment.class));

    actionBar.addTab(tab);

}
        如果Activity終止了,那麼你應該保存當前選擇的選項標籤的狀態,以便當用戶再次返回時,你能夠打開合適的選項標籤。在保存狀態的時刻,你能夠用getSelectedNavigationIndex()方法查詢當前的被選擇的選項標籤。這個方法返回被選擇的選項標籤的索引位置。
        注意:在某些情況下,Android系統會把action bar選項標籤作爲一個下拉列表來顯示,以便確保操作欄的最優化顯示。並且保存每個Fragment所必須的狀態是至關重要的,因爲當用戶用選項標籤在Fragment對象間切換時,它會查看Fragment在離開時樣子。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章