Android中的工具欄(ActionBar和ToolBar)

ActionBar和ToolBar

Action Bar是Android 3.0引入的導航欄功能,然而到5.0的時候,又推出了ToolBar,實際上這兩個可以理解為同一個東西,ToolBar是對ActionBar的升級,使用起來也基本是一樣的。只是因為ActionBar在實際使用過程中的各種問題,才推出了ToolBar來接替ActionBar。ActionBar通常翻譯為操作欄,而到了ToolBar則翻譯為工具欄,這里我們統稱為工具欄。

添加和隱藏工具欄

在Toolbar引入之前,添加ActionBar是通過Theme來實現的,在Manifest文件中指定Application或者Activity的Theme為Theme.Holo或者它的子類,運行以后ActionBar會自動添加進來。移除ActionBar也可以通過指定theme的方式,設置為Theme.Holo.NoActionBar。或者使用動態方式,先獲取到ActionBar,然后設置隱藏

ActionBar actionBar = getActionBar();  
actionBar.hide(); 

ToolBar的引入之后,Android已經不推薦我們這么操作了。應該采用ToolBar的方式來管理工具欄

為了能更好的向下兼容,官方推薦我們使用 v7 appcompat 來添加和管理ToolBar。添加ToolBar的步驟如下:

  1. 按照支持庫設置中所述向您的項目添加 v7 appcompat 支持庫。

  2. 確保 Activity 可以擴展 AppCompatActivity:

public class MyActivity extends AppCompatActivity {
  // ...
}

注:請為您應用中每個使用 Toolbar 作為應用欄的 Activity 進行此更改。

  1. 在應用清單中,將 <application> 元素設置為使用 appcompat 的其中一個 NoActionBar 主題。使用這些主題中的一個可以防止應用使用原生 ActionBar 類提供應用欄。例如:
<application
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    />

到這里為止,所做的工作是確保Activity中不包含默認的ActionBar,否則會引起崩潰。如果想保留theme,而這個theme又是包含ActionBar的,可以在Activity中調用requestWindowFeature(Window.FEATURE_NO_TITLE);,如果是繼承在AppCompatActivity,調用supportRequestWindowFeature(Window.FEATURE_NO_TITLE),這樣就可以去掉theme中自帶的ActionBar了

  1. 向 Activity 的布局添加一個 Toolbar。例如,以下布局代碼可以添加一個 Toolbar 并賦予其浮動在 Activity 之上的外觀:
< android.support.v7.widget.Toolbar
   android:id="@+id/my_toolbar"
   android:layout_width="match_parent"
   android:layout_height="?attr/actionBarSize"
   android:background="?attr/colorPrimary"
   android:elevation="4dp"
   android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
   app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

Material Design 規范建議應用欄具有 4 dp 的仰角。

將工具欄定位在 Activity 布局的頂部,因為您要使用它作為應用欄。

  1. 在 Activity 的 onCreate() 方法中,調用 Activity 的 setSupportActionBar() 方法,然后傳遞 Activity 的工具欄。該方法會將工具欄設置為 Activity 的應用欄。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();
    }

設置好ToolBar之后,如果想對他進行操作,再使用getSupportActionBar獲取到ActionBar對象,就可以按照ActionBar的操作方式來管理工具欄了

可以看出來,ToolBar可以作為一個UI單元,可以很方便的對每個Activity進行單獨設定管理,不再像ActionBar一樣,只能通過主題來管理。當然,如果對工具欄要求不高,仍然可以使用主題來指定ActionBar,但是要注意,如果你的Activity繼承自AppCompatActivity,使用的主題應該是Theme.AppCompat.,如果直接繼承自Activity,用Theme.AppCompat.是不起作用的!

管理工具欄

一個完整的工具欄主要組成部分如下:


ActionBar

現在我們來依次看一下各個部分是怎樣設置的

  • Navigation

    這是工具欄的層級導航功能,類似于按下Back鍵,但是,與Back鍵不同,這里需要我們指定返回的Activity。在Manifest文件里設置:

<activity
            android:name=".model.fragment.LandViewActivity"http://包含ToolBar的當前Activity
            android:parentActivityName=".SplashActivity"http://按下導航鍵返回的目標Activity
            >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".SplashActivity" />
        </activity>

這樣,層級導航的功能設置就完成了。當然還需要設置Navigation,如果不想使用默認的導航圖標,也可以自己在layout文件中指定:

app:navigationIcon="@drawable/ic_action_nav"

注意:使用ToolBar的時候,如果在Layout文件中沒有設置NavigationIcon,工具欄是不會顯示Navigation按鍵的。如果不想自定義圖標,可以在獲取到ActionBar對象之后,設置actionBar.setDisplayHomeAsUpEnabled(true)來啟用Navigation功能,這樣就可以使用系統自帶的圖標了。如果我們使用是ActionBar主題,Navigation功能默認是啟用的,設置parentActivity就可以了
Navigation返回的Activity并不是返回棧里存在的實例,而是重新創建的Activity,也就是說,之前Activity存在的狀態,從Navigation返回之后,并不會保存下來

  • Logo和Title

    這兩項的設置非常簡單,可以在layout文件中設置,也可以在代碼中對ActionBar對象進行設置,就不再介紹了。

  • Menu

    在工具欄上可以設置多個按鈕,Menu就是由這些按鈕組成的。
    要在工具欄上添加按鍵,需要先指定Menu文件,menu文件需要定義在res/menu文件夾下(toolbar_menu.xml):

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/add_item"
        android:icon="@drawable/ic_action_new"
        android:title="Add"
        app:showAsAction="ifRoom|withText"
        />
    <item
        android:id="@+id/remo_item"
        android:icon="@drawable/ic_action_remove"
        android:title="Remove"
        app:showAsAction="ifRoom|withText"
        />
    <item
        android:id="@+id/more_item"
        android:icon="@drawable/ic_action_more"
        android:title="Remove"
        app:showAsAction="never"
        />
</menu>

注意,因為例子中使用是v7支持庫,需要使用app命名空間。如果不使用支持庫可以直接使用android。app:showAsAction指定了按鍵的顯示方式。因為工具欄空間相對有限,我們可指定按鍵的顯示方式,never表示總在overflow menu中顯示,always表示總在工具欄顯示,ifRoom表示空間足夠則顯示在工具欄上,withText表示空間足夠的時候顯示Title,也可以用組合的方式:ifRoom|withTitle

Menu定義好之后,在Activity中添加并引用它:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.toobar_menu,menu);
        return super.onCreateOptionsMenu(menu);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            case R.id.remo_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            case R.id.more_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

這里是在Activity中直接加載menu,如果是Fragment中使用,會有所不同。Fragment中必須設置setHasOptionsMenu(true),它用來通知FragmentManager,當前Fragment需要調用onCreateOptionsMenu方法。

  • Navigation和Menu的關系

    實際上Navigation也屬于menu,它的id是android.R.id.home,可以在onOptionsItemSelected中對它進行監聽

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;  
        ......  
    }  
}  

調用NavUtils.getParentActivityIntent()方法可以獲取到跳轉至父Activity的Intent,然后如果父Activity和當前Activity是在同一個Task中的,則直接調用navigateUpTo()方法進行跳轉,如果不是在同一個Task中的,則需要借助TaskStackBuilder來創建一個新的Task。

OverFlow按鈕顯示圖標

overflow中的按鈕默認是不顯示圖標的,它由MenuBuilder這個類的setOptionalIconsVisible方法來決定,如果我們在overflow被展開的時候給這個方法傳入true,那么里面的每一個Action按鈕對應的圖標就都會顯示出來了。

@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);  
}  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容