Android Toolbar使用及Fragment中的Toolbar處理

來源:互聯網
上載者:User

標籤:clear   檔案   source   roo   adl   如何   https   design   ase   

Toolbar作為ActionBar使用介紹

本文介紹了在Android中將Toolbar作為ActionBar使用的方法.
並且介紹了在Fragment和嵌套Fragment中使用Toolbar作為ActionBar使用時需要注意的事項.

使用support library的Toolbar

Android的ActionBar每個版本都會做一些改變, 所以原生的ActionBar在不同的系統上看起來可能會不一樣.
使用support library版本的Toolbar可以讓你的應用在多種裝置類型上保持一致. support library中總是包含了最新的features.
Android從5.0 (API Level 21)開始提供Material Design, 使用v7版本的Toolbar後, 在任何Android 2.1(API Level 7)以上的機器上都可以看到Material Design風格的Toolbar.

在Activity中使用Toolbar

1.首先項目gradle中添加:

compile ‘com.android.support:appcompat-v7:23.4.0‘

2.確保Activity繼承AppCompatActivity

3.在application設定中使用NoActionBar的主題:

<application    android:theme="@style/Theme.AppCompat.Light.NoActionBar"    />

4.把Toolbar寫在布局中

<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"/>

5.在Activity裡面把Toolbar設定成為ActionBar

首先把Toolbar find出來, 然後調用setSupportActionBar方法
把Toolbar設定為自己的ActionBar即可.

public class ToolbarDemoActivity extends AppCompatActivity {    @BindView(R.id.toolbar)    Toolbar toolbar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_toolbar_demo);        ButterKnife.bind(this);        setSupportActionBar(toolbar);    }}

然後就可以隨意使用啦, 用getSupportActionBar可以擷取ActionBar類型的對象, 從而使用ActionBar的方法.

添加Action Buttons

定義menu:

<?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/action_android"        android:icon="@drawable/ic_android_black_24dp"        android:title="@string/action_android"        app:showAsAction="always" />    <item        android:id="@+id/action_favourite"        android:icon="@drawable/ic_favorite_black_24dp"        android:title="@string/action_favourite"        app:showAsAction="ifRoom" />    <item        android:id="@+id/action_settings"        android:title="@string/action_settings"        app:showAsAction="never" /></menu>

然後在代碼中inflate和處理它的點擊事件:

@Overridepublic boolean onCreateOptionsMenu(Menu menu) {    Log.i(TAG, "onCreateOptionsMenu()");    getMenuInflater().inflate(R.menu.menu_activity_main, menu);    return super.onCreateOptionsMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {    switch (item.getItemId()) {        case R.id.action_android:            Log.i(TAG, "action android selected");            return true;        case R.id.action_favourite:            Log.i(TAG, "action favourite selected");            return true;        case R.id.action_settings:            Log.i(TAG, "action settings selected");            return true;        default:            return super.onOptionsItemSelected(item);    }}

 

添加向上返回的action

添加向上返回parent的action:

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_toolbar_demo);    ButterKnife.bind(this);    setSupportActionBar(toolbar);    // add a left arrow to back to parent activity,    // no need to handle action selected event, this is handled by super    getSupportActionBar().setDisplayHomeAsUpEnabled(true);}

然後只需要在manifest中指定parent:

<activity    android:name=".toolbar.ToolbarDemoActivity"    android:parentActivityName=".MainActivity"></activity>

在Fragment中使用Toolbar

在Fragment中使用Toolbar的步驟和Activity差不多.
在Fragment布局中添加一個Toolbar, 然後find它, 然後調用Activity的方法來把它設定成ActionBar:

((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

注意此處有一個強轉, 必須是AppCompatActivity才有這個方法.

但是此時運行到Fragment之後, 發現Toolbar上的文字和按鈕全是Activity傳過來的, 這是因為只有Activity的onCreateOptionsMenu()被調用了, 但是Fragment的並沒有被調用.
在Fragment中加上這句:

setHasOptionsMenu(true);

此時Fragment的onCreateOptionsMenu()回調會被調到了, 但是inflate出的按鈕和Activity中的actions加在一起顯示出來了.

因為Activity的onCreateOptionsMenu()會在之前調用到.
於是Fragment中的寫成這樣:

@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {    Log.e(TAG, "onCreateOptionsMenu()");    menu.clear();    inflater.inflate(R.menu.menu_parent_fragment, menu);}

即先clear()一下, 這樣按鈕就只有Fragment中設定的自己的了, 不會有Activity中的按鈕.

在嵌套的子Fragment中使用Toolbar

前面已經介紹過, Fragment可以嵌套使用: Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常見錯誤.
那麼在前面的Fragment中再顯示一個子Fragment, 並且又帶有一個不一樣的Toolbar, 還需要哪些處理呢?
首先, java代碼中還是需要有:

setHasOptionsMenu(true)((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

然後根據是否需要功能表按鈕, 覆寫onCreateOptionsMenu()方法來inflate自己的menu檔案即可.

感覺和在普通的Fragment中使用Toolbar作為ActionBar並沒有什麼區別.
但是如果你的多個Fragment有不同的Toolbar菜單選項, 如果你沒有懂得其中的原理, 可能就會出現一些混亂.
下面來解說一下相關的方法.

onCreateOptionsMenu()方法的調用

一旦調用

((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

就會導致ActivityonCreateOptionsMenu()方法的調用, 而Activity會根據其中Fragment是否設定了setHasOptionsMenu(true)來調用Fragment的
onCreateOptionsMenu()方法, 調用順序是樹形的, 按層級調用, 中間如果有false則跳過.

假設當前Activity, Parent Fragment和Child Fragment中都設定了自己的Toolbar為ActionBar.
在開啟Child fragment的時候, onCreateOptionsMenu()的調用順序是.
Activity -> Parent -> Child. 此時parent和child fragment都設定了setHasOptionsMenu(true).

關於這個, 還有以下幾種情況:

- 如果Parent的`setHasOptionsMenu(false)`, Child為true, 則Parent的`onCreateOptionsMenu()`不會調用, 開啟Child的時候Activity -> Child.- 如果Child的`setHasOptionsMenu(false)`, Parent為true, 則開啟Child的時候仍然會調用Activity和Parent的onCreateOptionsMenu()方法.- 如果Parent和Child都置為false, 開啟Parent和Child Fragment的時候都會調用Activity的onCreateOptionsMenu()方法.

僅僅是child Fragment的show() hide()的切換, activity和parent Fragment的onCreateOptionsMenu()也會重新進入.
這一點我還沒有想明白, 是項目中遇到的, 初步推測可能是menu的顯隱變化invalidate了menu, 改天有空再試試.

上面的機制常常是導致Toolbar上面的按鈕混淆錯亂的原因.
舉個例子:
如果我們現在Activity和Parent Fragment有不同的Toolbar按鈕, 但是Child只有文字, 沒有按鈕.
很顯然我們不需要給child寫menu檔案, 也不需要覆寫child裡的onCreateOptionsMenu()方法.
但是此時不管怎樣, parent的onCreateOptionsMenu()方法都會被調用, 這樣我們開啟child的時候, toolbar上就神奇地出現了parent裡的按鈕.
這種情況如何解決呢?
可以在parent中加一個條件, 當沒有child fragment的時候才做inflate的工作:

@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {    Log.e(TAG, "onCreateOptionsMenu()");    menu.clear();    if (getChildFragmentManager().getBackStackEntryCount() == 0) {        inflater.inflate(R.menu.menu_parent_fragment, menu);    }}

另外, 除了setSupportActionBar()之外, 如果我們想主動觸發 onCreateOptionsMenu()方法的調用, 可以用

invalidateOptionsMenu()方法.

onOptionsItemSelected()方法的調用

在Activity和其中的Fragment都有options menu的時候, 需要注意menu item的id不要重複.
以為點擊事件的分發也是從Activity開始分發下去的, 如果child fragment中有個選項的id和Activity中一個選項的id重複了, 則在Activity中就會將其處理, 不會繼續分發.

有嵌套Fragment時 Back鍵處理

之前沒有嵌套Fragment的情況下, 只要將Fragment加入到Back Stack中, 那麼按下Back鍵的時候pop動作是系統自動做好的.
雖然在添加child fragment的時候將其加入到back stack中, 但是按back鍵的時候仍然是將parent fragment彈出, 只剩下Activity.
這是因為back鍵只檢查第一層Fragment的back stack, 對於child fragment, 需要在其parent中自己處理.
比如這樣處理:

在Activity中

@Overridepublic void onBackPressed() {    Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content);    if (fragment instanceof ToolbarFragment) {        if (((ToolbarFragment) fragment).onBackPressed()) {            return;        }    }    super.onBackPressed();}

其中ToolbarFragment是直接加在Activity中作為parent fragment的.

在parent fragment中(即ToolbarFragment中):

public boolean onBackPressed() {    return getChildFragmentManager().popBackStackImmediate();}

本文Demo地址: Demo on github

其中的: ToolbarDemoActivity即為Toolbar Demo.
本文地址: Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar處理

Android Toolbar使用及Fragment中的Toolbar處理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.