android ActionBar與Menu - 1 - api demos 學(xué)習(xí)
android ActionBar與Menu - 2 - email中ActionBar分析
?
這里以Email為例,簡單分析一下ActionBar在實(shí)際中的應(yīng)用
上面是在模擬器上登錄原生Email的截圖
?
這里說一下所謂的原生:
原生不是指大家買來手機(jī)之后沒有修改過任何內(nèi)容,軟件本身的樣子。也不是指google的各種親兒子本身的樣子,因?yàn)闊o論是前者還是后者,最起碼都是要經(jīng)過優(yōu)化和修復(fù)bug的,不是親兒子那就很有可能進(jìn)行了整容,讓你看不出原來的樣子
這里的原生是用google發(fā)布的源碼編譯出來的apk,安裝到手機(jī)或模擬器上面大家就可以看到
?
我們主要看看Email如何使用ActionBar和menu的
頁面可以發(fā)現(xiàn),Email既有AcionBar又有menu,menu被放在了底部,先看ActionBar
Email的主Activity是EmailActivity,我就不畫類圖了,因?yàn)榭偸钱嫴幻靼?,怕誤導(dǎo)大家,所以就用類似堆棧log的形式來介紹
@Override
protected void onCreate(Bundle savedInstanceState) {
……
initUIController();
……
}
private void initUIController() {
mUIController = UiUtilities.useTwoPane(this)
? new UIControllerTwoPane(this) : new UIControllerOnePane(this);
}
這里初始化了一個(gè)UIController,其中的關(guān)系是這樣的
UIControllerBase為父類,是一個(gè)抽象類,下面有兩個(gè)實(shí)現(xiàn)類分別為UIControllerOnePane和UIControllerTwoPane(實(shí)在理解不了為什么這么命名。。。)
UIControllerOnePane為手機(jī)UI實(shí)現(xiàn),UIControllerTwoPane為平板UI實(shí)現(xiàn),我們這里只考慮UIControllerOnePane
public UIControllerBase(EmailActivity activity) {
mActivity = activity;
mFragmentManager = activity.getFragmentManager();
mRefreshManager = RefreshManager.getInstance(mActivity);
mActionBarController = createActionBarController(activity);
if (DEBUG_FRAGMENTS) {
FragmentManager.enableDebugLogging(true);
}
}
這里包含了一個(gè)ActionBarController,createActionBarController是抽象方法,下面是UIControllerOnePane的實(shí)現(xiàn)
@Override
protected ActionBarController createActionBarController(Activity activity) {
// For now, we just reuse the same action bar controller used for 2-pane.
// We may change it later.
return new ActionBarController(activity, activity.getLoaderManager(),
activity.getActionBar(), new ActionBarControllerCallback());
}
最關(guān)鍵的就是ActionBarController了,它包含ActionBar所有內(nèi)容
public ActionBarController(Context context, LoaderManager loaderManager,
ActionBar actionBar, Callback callback) {
mContext = context;
mLoaderManager = loaderManager;
mActionBar = actionBar;
mCallback = callback;
mDelayedOperations = new DelayedOperations(Utility.getMainThreadHandler());
mAllFoldersLabel = mContext.getResources().getString(
R.string.action_bar_mailbox_list_title);
mAccountsSelectorAdapter = new AccountSelectorAdapter(mContext);
// Configure action bar.
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_CUSTOM);
// Prepare the custom view
mActionBar.setCustomView(R.layout.action_bar_custom_view);
mActionBarCustomView = (ViewGroup) mActionBar.getCustomView();
// Account spinner
mAccountSpinnerContainer =
UiUtilities.getView(mActionBarCustomView, R.id.account_spinner_container);
mAccountSpinner = UiUtilities.getView(mActionBarCustomView, R.id.account_spinner);
mAccountSpinnerDefaultBackground = mAccountSpinner.getBackground();
mAccountSpinnerLine1View = UiUtilities.getView(mActionBarCustomView, R.id.spinner_line_1);
mAccountSpinnerLine2View = UiUtilities.getView(mActionBarCustomView, R.id.spinner_line_2);
mAccountSpinnerCountView = UiUtilities.getView(mActionBarCustomView, R.id.spinner_count);
// Account dropdown
mAccountDropdown = new AccountDropdownPopup(mContext);
mAccountDropdown.setAdapter(mAccountsSelectorAdapter);
mAccountSpinner.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
if (mAccountsSelectorAdapter.getCount() > 0) {
mAccountDropdown.show();
}
}
});
}
?從上面可以看出,ActionBar實(shí)際上也不復(fù)雜,只是設(shè)置了顯示選項(xiàng)和一個(gè)CustomView,復(fù)雜的內(nèi)容幾乎全部集中在這個(gè)CustomView上了
// Configure action bar.
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_CUSTOM);
// Prepare the custom view
mActionBar.setCustomView(R.layout.action_bar_custom_view);
mActionBarCustomView = (ViewGroup) mActionBar.getCustomView();
當(dāng)點(diǎn)擊CustomView時(shí)候會有彈出下拉框,mAccountDropdown就發(fā)揮作用了
private class AccountDropdownPopup extends ListPopupWindow
設(shè)置了mAccountSpinner.setOnClickListener,調(diào)用到mAccountDropdownshow()
mAccountDropdownshow顯示由mAccountsSelectorAdapter提供
public class AccountSelectorAdapter extends CursorAdapter
其中的數(shù)據(jù)由CursorWithExtras com.android.email.activity.ActionBarController.mCursor提供
mCursor只在一個(gè)地方進(jìn)行刷新,那就是加載賬戶郵箱信息的時(shí)候
/**
* Load account/mailbox info, and account/recent mailbox list.
*/
private void loadAccountMailboxInfo(final long accountId, final long mailboxId) {
mLoaderManager.restartLoader(LOADER_ID_ACCOUNT_LIST, null,
new LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return AccountSelectorAdapter.createLoader(mContext, accountId, mailboxId);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mCursor = (AccountSelectorAdapter.CursorWithExtras) data;
updateTitle();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mCursor = null;
updateTitle();
}
});
}
我們可以發(fā)現(xiàn),加載完畢之后Cursor更新了,然后updateTitle,不用去看函數(shù)也能猜出這里是更新ActionBar
為了刷新列表,調(diào)用了下面語句
mAccountsSelectorAdapter.swapCursor(mCursor);
updateTitle就不再進(jìn)行分析了,里面幾乎都是刷新那個(gè)CustomView的內(nèi)容
?
下面看看底部的菜單,之前的學(xué)習(xí)中,api demos里并沒有演示這種情況,我們用hierarchyviewer查看,發(fā)現(xiàn)頁面上下都是一個(gè)ActionBarContainer的容器
上面的ActionBar我們已經(jīng)知道它是怎么來的了,那下面的呢?原因在于manifest的配置
?
<activity
android:name=".activity.EmailActivity"
android:uiOptions="splitActionBarWhenNarrow"
>
</activity>
splitActionBarWhenNarrow使得ActionBar被拆分成上下兩個(gè)部分
splitActionBarWhenNarrow 用于顯示Activity在窄屏設(shè)備(如豎屏手機(jī))上運(yùn)行時(shí)的所有menu項(xiàng)。當(dāng)然,如果手機(jī)有menu鍵的時(shí)候,當(dāng)menu項(xiàng)過多而顯示不下的時(shí)候按Menu鍵即可
這時(shí)迷題已解,沒有什么神秘的地方了,看看menu配置,一目了然
?
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/compose"
android:orderInCategory="100"
android:alphabeticShortcut="c"
android:title="@string/compose_action"
android:icon="@drawable/ic_menu_compose_normal_holo_light"
android:showAsAction="ifRoom"
/>
<item
android:id="@+id/search"
android:orderInCategory="200"
android:alphabeticShortcut="s"
android:title="@string/search_action"
android:icon="@drawable/ic_menu_search_holo_light"
android:showAsAction="ifRoom"
/>
<item
android:id="@+id/show_all_mailboxes"
android:orderInCategory="300"
android:alphabeticShortcut="c"
android:title="@string/mailbox_list_account_selector_show_all_folders"
android:icon="@drawable/ic_menu_move_to_holo_light"
android:showAsAction="ifRoom"
/>
<item
android:id="@+id/refresh"
android:orderInCategory="400"
android:alphabeticShortcut="r"
android:title="@string/refresh_action"
android:icon="@drawable/ic_menu_refresh_holo_light"
android:showAsAction="ifRoom"
/>
<!-- Note the order; we want to show them to the right of delete/move -->
<item
android:id="@+id/newer"
android:orderInCategory="1500"
android:icon="@drawable/menu_item_newer"
android:showAsAction="always"
android:visible="false"
/>
<item
android:id="@+id/older"
android:orderInCategory="1600"
android:icon="@drawable/menu_item_older"
android:showAsAction="always"
android:visible="false"
/>
<item
android:id="@+id/mailbox_settings"
android:orderInCategory="2000"
android:title="@string/mailbox_settings_action"
android:icon="@android:drawable/ic_menu_preferences"
/>
<item
android:id="@+id/account_settings"
android:orderInCategory="3000"
android:title="@string/settings_action"
android:icon="@android:drawable/ic_menu_preferences"
/>
</menu>
當(dāng)我們橫屏的時(shí)候,menu就會跑到上面去了
?
?
下面是帶回退導(dǎo)航的
他能使用戶回到上一個(gè)頁面(并不是上一個(gè)activity,回到上一個(gè)activity可以通過按back鍵實(shí)現(xiàn))
?
mActionBar.setDisplayOptions(showUp ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP);
在之前的refreshInernal中已經(jīng)設(shè)置過了
?
當(dāng)我們打開或新建一個(gè)郵件的時(shí)候,頁面會跳轉(zhuǎn)到新的activity
public class MessageCompose extends Activity implements OnClickListener, OnFocusChangeListener, DeleteMessageConfirmationDialog.Callback, InsertQuickResponseDialog.Callback
這里我們看到了,頁面依然有回退導(dǎo)航,點(diǎn)擊之后能回退到上一個(gè)頁面,當(dāng)然,不再是當(dāng)前的activity了
那么它是如何做到的,代碼如下
?
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (handleCommand(item.getItemId())) {
return true;
}
return super.onOptionsItemSelected(item);
}
private boolean handleCommand(int viewId) {
switch (viewId) {
case android.R.id.home:
onBack(false /* systemKey */);
return true;
……
}
/**
* Handle a tap to the system back key, or the "app up" button in the action bar.
* @param systemKey whether or not the system key was pressed
*/
private void onBack(boolean systemKey) {
finish();
if (isOpenedFromWithinApp()) {
// If opened from within the app, we just close it.
return;
}
if (isOpenedFromWidget() || !systemKey) {
// Otherwise, need to open the main screen for the appropriate account.
// Note that mAccount should always be set by the time the action bar is set up.
startActivity(Welcome.createOpenAccountInboxIntent(this, mAccount.mId));
}
}
點(diǎn)擊回退導(dǎo)航時(shí),觸發(fā)的menu是android.R.id.home?
剩下的事情就好辦了,這里交給了onBack來處理
?
?
至此Email應(yīng)用的ActionBar和menu就基本分析完了,如果有不準(zhǔn)確的地方還希望大家指正
?
?
最后附上別人的幾篇翻譯,內(nèi)容很基礎(chǔ),也比api demos多,值得一看
Android 用戶界面---操作欄(Action Bar 一) :基本操作
Android 用戶界面---操作欄(Action Bar 二) :分離式ActionBar與回退導(dǎo)航
Android 用戶界面---操作欄(Action Bar 三) :ActionView
Android 用戶界面---操作欄(Action Bar 四) :ActionProvider與Tab
Android 用戶界面---操作欄(Action Bar 五) :主要是關(guān)于樣式
?
?
轉(zhuǎn)貼請保留以下鏈接
本人blog地址
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

