天天看點

ToolBar使用詳解簡單使用:深入分析:

請尊重他人勞動成果,請勿随意剽竊,轉載請注明,謝謝!轉載請注明出處:http://blog.csdn.net/evan_man/article/details/51684947

注意:使用ToolBar的話,一定要将目前Activity或者Application的Theme設定為NoActionBar樣式,如<style name=”AppTheme” parent=”Theme.AppCompat.Light.NoActionBar”>,否則ActionBar和ToolBar兩者都會顯示,而且setSupportActionBar方法将會抛出異常,其實使用了ToolBar完全可以把ActionBar抛到一邊去,隻是使用ToolBar就能完成所有ActionBar的功能。

    ToolBar是在Android5.0中提出來的,ActionBar在Android3.0提出來的。ActionBar是系統為我們建立一個View并顯示在應用的頂端,直接繼承自Object,是以我們如果要對這塊内容的視圖進行定制就需要嚴格按照ActionBar的方式進行工作。ToolBar是一個繼承自ViewGroup的控件,是以我們可以用ViewGroup的方式去建立任何我們想要的視圖内容,也可在布局檔案中寫入我們想要的内容,是以ToolBar比ActionBar更加靈活。同時ToolBar相對于ViewGroup的好處在于, 提供了更多便捷的方法來控制顯示方式,這些方式主要是針對标題欄的特性而定制的,比如我們可以通過setTitle方法為其設定标題。 下圖是網上找的Toolbar提供的便捷方法所對應的修改的内容:

ToolBar使用詳解簡單使用:深入分析:

上圖對應方法有:toolbar.setTitle(“AndroidViewDemo”); 、 toolbar.inflateMenu(R.menu.ac_toolbar_menu); 、 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {…}等。     Toolbar與ActionBar一樣也支援對彈出菜單樣式的修改,隻不過在将Toolbar單獨作為控件使用的情況下不能像ActionBar那樣便捷地通過Theme來修改,Toolbar提供了一個setPopupTheme方法和對應的app.popupTheme屬性來設定彈出菜單的樣式。     标題欄本身就是一個特殊的View為何不然View自己來處理呢?是以還是建議使用ToolBar的。如果你習慣了ActionBar那麼你也可以在建立完Toolbar之後通過setSupportActionBar方法将Toolbar設定為目前Activity的ActionBar,之後的所有操作跟ActionBar都是一樣的了。

簡單使用:

一、編寫菜單欄布局(标題欄右邊最多顯示三個Action,其餘則隐藏) menu_main.xml

[html]

view plain copy print ?

  1. <menu xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     xmlns:app=“http://schemas.android.com/apk/res-auto”>  
  3.     <item  
  4.         android:id=“@+id/menu_tool”  
  5.         android:icon=“@drawable/toolbar1”  
  6.         app:showAsAction=“ifRoom”  
  7.         android:orderInCategory=“50”  
  8.         android:title=“Tool”>  
  9.     </item>  
  10.     <item  
  11.         android:id=“@+id/menu_finder”  
  12.         android:icon=“@drawable/toolbar2”  
  13.         app:showAsAction=“ifRoom”  
  14.         android:orderInCategory=“10”  
  15.         android:title=“Find”>  
  16.     </item>  
  17. </menu>  
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_tool"
        android:icon="@drawable/toolbar1"
        app:showAsAction="ifRoom"
        android:orderInCategory="50"
        android:title="Tool">
    </item>
    <item
        android:id="@+id/menu_finder"
        android:icon="@drawable/toolbar2"
        app:showAsAction="ifRoom"
        android:orderInCategory="10"
        android:title="Find">
    </item>
</menu>           

注意 :     android:title=”XX”屬性用于設定當該item在overflow menu顯示時顯示的文字内容。app:showAsAction=”ifRoom”  用于設定在有足夠空間的情況下在toolbar中顯示Action的圖示。

二、main_activity.xml布局檔案中加入<Toolbar/>标簽

[html]

view plain copy print ?

  1. <android.support.v7.widget.Toolbar xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     xmlns:app=“http://schemas.android.com/apk/res-auto”  
  3.     android:id=“@+id/toolbar”  
  4.     android:layout_width=“match_parent”  
  5.     android:layout_height=“wrap_content”  
  6.     android:minHeight=“?attr/actionBarSize”  
  7.     android:background=“?attr/colorPrimary”  
  8.     app:contentInsetStart=“0dp”  
  9.     app:contentInsetLeft=“0dp”  
  10.     app:theme=“@style/MyToolBarTheme”  
  11.     app:titleTextAppearance=“@style/Toolbar.TitleText”  
  12.     >  
  13.     <!–此處可以加你想要的View控件,如同LinearLayout類似的使用–>  
  14. </android.support.v7.widget.Toolbar>  
  15. <!–android:contentInsertStart  contentInsetLeft是沒有效果的不能保證控件靠近左邊顯示–>  
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:contentInsetStart="0dp"
    app:contentInsetLeft="0dp"
    app:theme="@style/MyToolBarTheme"
    app:titleTextAppearance="@style/Toolbar.TitleText"
    >
    <!--此處可以加你想要的View控件,如同LinearLayout類似的使用-->
</android.support.v7.widget.Toolbar>

<!--android:contentInsertStart  contentInsetLeft是沒有效果的不能保證控件靠近左邊顯示-->           

ToolBar在此可以就看成一個普通的ViewGroup,是以它顯示的位置可以随意設定,但是如果要模拟ActionBar的功能,則需要将其放置在視圖的最頂部。

 三、Activity中擷取ToolBar控件并做相應設定 1、初始化

[java]

view plain copy print ?

  1. protected void onCreate(Bundle savedInstanceState) {  
  2.         super.onCreate(savedInstanceState);  
  3.         toolbar = (Toolbar)findViewById(R.id.toolbar);  
  4.         toolbar.setNavigationIcon(R.mipmap.back);   
  5.         //設定标題欄左邊的圖示樣式,對應id為android.id.home ,用于傳回上一級目錄  
  6.         setSupportActionBar(toolbar);  
  7.         //将ToolBar對象設定為目前Activity的ActionBar  
  8. }  
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        toolbar = (Toolbar)findViewById(R.id.toolbar);
        toolbar.setNavigationIcon(R.mipmap.back); 
        //設定标題欄左邊的圖示樣式,對應id為android.id.home ,用于傳回上一級目錄
        setSupportActionBar(toolbar);
        //将ToolBar對象設定為目前Activity的ActionBar
}           

2、加載顯示Menu布局,重寫Activity的onCreateOptionMenu方法

[cpp]

view plain copy print ?

  1. @Override  
  2.     public boolean onCreateOptionsMenu(Menu menu) {  
  3.         getMenuInflater().inflate(R.menu.menu_main, menu);  
  4.         return true;  
  5. }  
@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
}           

3、監聽标題欄中的點選事件

[cpp]

view plain copy print ?

  1. @Override  
  2.     public boolean onOptionsItemSelected(MenuItem item) {  
  3.         switch (item.getItemId()){  
  4.             case R.id.menu_finder:  
  5.                 Toast.makeText(MainActivity.this,“touch finderItem”,Toast.LENGTH_SHORT).show();  
  6.                 AndroidUtils.changeActivity(this,SearchActivity.class); //跳轉到搜尋頁Activity  
  7.                 break;  
  8.             case R.id.menu_tool:  
  9.                 Toast.makeText(MainActivity.this,“touch toolItem”,Toast.LENGTH_SHORT).show();  
  10.                 AndroidUtils.showPopupMenu(this,toolbar,R.menu.popmenu,new OnPopupMenuItemClickListener(this)); //彈出共享菜單  
  11.                 break;  
  12.             case android.R.id.home:  
  13.                 Toast.makeText(MainActivity.this,“touch up navigation”,Toast.LENGTH_SHORT).show();  
  14.                 AndroidUtils.backToParent(this); //傳回上一級目錄  
  15.                 break;  
  16.             default: return super.onOptionsItemSelected(item);  
  17.         }  
  18.         return true;  
  19. }  
  20.      public static void showPopupMenu(Context context,  
  21.                                      View v,int menuResId, PopupMenu.OnMenuItemClickListener onMenuItemClickListener,  
  22.                                      PopupMenu.OnDismissListener onDismissListener,int gravity){  
  23.         PopupMenu popup = new PopupMenu(context, v);  
  24.         MenuInflater inflater = popup.getMenuInflater();  
  25.         inflater.inflate(menuResId, popup.getMenu());  
  26.         //利用反射顯示圖示  
  27.         try {  
  28.             Field field = popup.getClass().getDeclaredField(”mPopup”);  
  29.             field.setAccessible(true);  
  30.             MenuPopupHelper mHelper = (MenuPopupHelper) field.get(popup);  
  31.             mHelper.setForceShowIcon(true);  
  32.         } catch (IllegalAccessException | NoSuchFieldException e) {  
  33.             e.printStackTrace();   }  
  34.         popup.setOnMenuItemClickListener(onMenuItemClickListener);  
  35.         if(onDismissListener!=null) popup.setOnDismissListener(onDismissListener);  
  36.         popup.setGravity(gravity);  
  37.         popup.show();  
  38.     }  
  39.     public static void backToParent(Activity activity){  
  40.         Intent upIntent = NavUtils.getParentActivityIntent(activity);  
  41.         if(upIntent == null) {  
  42.             activity.finish();  
  43.             return;  
  44.         }  
  45.         if (NavUtils.shouldUpRecreateTask(activity, upIntent)) {  
  46.             // This activity is NOT part of this app’s task, so create a new task  
  47.             // when navigating up, with a synthesized back stack.  
  48.             TaskStackBuilder.create(activity)  
  49.                     // Add all of this activity’s parents to the back stack  
  50.                     .addNextIntentWithParentStack(upIntent)  
  51.                             // Navigate up to the closest parent  
  52.                     .startActivities();  
  53.         } else {  
  54.             // This activity is part of this app’s task, so simply  
  55.             // navigate up to the logical parent activity.  
  56.             NavUtils.navigateUpTo(activity, upIntent);  
  57.         }  
  58.     }  
@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.menu_finder:
                Toast.makeText(MainActivity.this,"touch finderItem",Toast.LENGTH_SHORT).show();
                AndroidUtils.changeActivity(this,SearchActivity.class); //跳轉到搜尋頁Activity
                break;
            case R.id.menu_tool:
                Toast.makeText(MainActivity.this,"touch toolItem",Toast.LENGTH_SHORT).show();
                AndroidUtils.showPopupMenu(this,toolbar,R.menu.popmenu,new OnPopupMenuItemClickListener(this)); //彈出共享菜單
                break;
            case android.R.id.home:
                Toast.makeText(MainActivity.this,"touch up navigation",Toast.LENGTH_SHORT).show();
                AndroidUtils.backToParent(this); //傳回上一級目錄
                break;
            default: return super.onOptionsItemSelected(item);
        }
        return true;
}
    /**
     * 彈出共享菜單
     */
     public static void showPopupMenu(Context context,
                                     View v,int menuResId, PopupMenu.OnMenuItemClickListener onMenuItemClickListener,
                                     PopupMenu.OnDismissListener onDismissListener,int gravity){
        PopupMenu popup = new PopupMenu(context, v);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(menuResId, popup.getMenu());
        //利用反射顯示圖示
        try {
            Field field = popup.getClass().getDeclaredField("mPopup");
            field.setAccessible(true);
            MenuPopupHelper mHelper = (MenuPopupHelper) field.get(popup);
            mHelper.setForceShowIcon(true);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();   }
        popup.setOnMenuItemClickListener(onMenuItemClickListener);
        if(onDismissListener!=null) popup.setOnDismissListener(onDismissListener);
        popup.setGravity(gravity);
        popup.show();
    }
    /**
     * 跳轉到父Activity
     */
    public static void backToParent(Activity activity){
        Intent upIntent = NavUtils.getParentActivityIntent(activity);
        if(upIntent == null) {
            activity.finish();
            return;
        }
        if (NavUtils.shouldUpRecreateTask(activity, upIntent)) {
            // This activity is NOT part of this app's task, so create a new task
            // when navigating up, with a synthesized back stack.
            TaskStackBuilder.create(activity)
                    // Add all of this activity's parents to the back stack
                    .addNextIntentWithParentStack(upIntent)
                            // Navigate up to the closest parent
                    .startActivities();
        } else {
            // This activity is part of this app's task, so simply
            // navigate up to the logical parent activity.
            NavUtils.navigateUpTo(activity, upIntent);
        }
    }           

注意:  NavUtils 類的靜态方法navigateUpFromSameTask()的效果是:finishes目前Activity并start或者resume其父Activity,如果父Activity在任務的傳回棧中,那麼正常回退。注意該方法僅僅适用于當目前應用是目前任務的所有者時方可使用。如果目前應用不是目前任務的所有者時,需要建立一個新的傳回棧,如果你Activity能夠接受其它應用通過Intent開啟你的Activity,那麼就需要注意這樣的處理,具體内容就是第三步的case android.R.id.home下面的内容。如果你期望回退到父Activity時,其還能保持原來的狀态,那麼父Activity可能需要設定啟動方式為android:launchMode=”singleTop”。

 (補充)四、Fragment中使用ToolBar

[cpp]

view plain copy print ?

  1. @Override  public void onCreate(Bundle savedInstanceState) {   
  2.     super.onCreate(savedInstanceState);  
  3.     // …  
  4.     setHasOptionsMenu(true);  
  5. }  
  6. @Override  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {   
  7.     // Inflate the menu; this adds items to the action bar.  
  8.     inflater.inflate(R.menu.my_menu, menu);    
  9.     // …  
  10. }  
  11. @Override  public boolean onOptionsItemSelected(MenuItem item) {   
  12.    // handle item selection  
  13.    switch (item.getItemId()) {  
  14.       case R.id.my_item:  
  15.          // Handle this selection  
  16.          return true;  
  17.       default:  
  18.          return super.onOptionsItemSelected(item);  
  19.    }  
  20. }  
@Override  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);
    // ...
    setHasOptionsMenu(true);
}
@Override  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    // Inflate the menu; this adds items to the action bar.
    inflater.inflate(R.menu.my_menu, menu);  
    // ...
}
@Override  public boolean onOptionsItemSelected(MenuItem item) { 
   // handle item selection
   switch (item.getItemId()) {
      case R.id.my_item:
         // Handle this selection
         return true;
      default:
         return super.onOptionsItemSelected(item);
   }
}           

可以發現Fragment除了第一步之外其它都是和Activity類似的。

(補充)五、ToolBar的Style設定

ToolBar的構造器中有如下一行語句: final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), null,   R.styleable.Toolbar, R.attr.toolbarStyle, 0);方法底層會調用 TypedArray array = context.obtainStyledAttributes(null,   R.styleable.Toolbar, R.attr.toolbarStyle, 0);即從主題中定義的toolbarStyle樣式檔案中和主題直接定義的屬性中擷取到如下屬性:

[html]

view plain copy print ?

  1. <declare-styleable name=“Toolbar”>  
  2.     <attr format=“reference” name=“titleTextAppearance”/>  
  3.     <attr format=“reference” name=“subtitleTextAppearance”/>  
  4.     <attr name=“title”/>  
  5.     <attr name=“subtitle”/>  
  6.     <attr name=“android:gravity”/>  
  7.     <attr format=“dimension” name=“titleMargins”/>  
  8.     <attr format=“dimension” name=“titleMarginStart”/>  
  9.     <attr format=“dimension” name=“titleMarginEnd”/>  
  10.     <attr format=“dimension” name=“titleMarginTop”/>  
  11.     <attr format=“dimension” name=“titleMarginBottom”/>  
  12.     <attr name=“contentInsetStart”/>  
  13.     <attr name=“contentInsetEnd”/>  
  14.     <attr name=“contentInsetLeft”/>  
  15.     <attr name=“contentInsetRight”/>  
  16.     <attr format=“dimension” name=“maxButtonHeight”/>  
  17.     <attr format=“reference” name=“collapseIcon”/>  
  18.     <attr format=“string” name=“collapseContentDescription”/>  
  19.     <attr name=“Theme”/> <!–這裡可以修改ToolBar除了PopupMenu的所有資訊(如背景色:注意java代碼中的setBackgroundColor這個方法不要用存在bug!!!效果不好,使用這裡的background屬性進行設定) 設定的值可以參考主題ThemeOverlay.AppCompat.Dark.ActionBar–>  
  20.     <attr name=“popupTheme”/>  <!–這裡隻能修改由ToolBar建立的彈出菜單,而對于自己通過建立PopupMenu對象顯示的隻能通過對context設定對應的主題進行設定,設定的值可以參考ThemeOverlay.AppCompat.Light–>  
  21.     <attr format=“reference” name=“navigationIcon”/>  
  22.     <attr format=“string” name=“navigationContentDescription”/>  
  23.     <attr name=“android:minHeight”/>  
  24.     <attr name=“logo”/>  
  25.     <attr format=“string” name=“logoDescription”/>  
  26.     <attr format=“color” name=“titleTextColor”/>  
  27.     <attr format=“color” name=“subtitleTextColor”/>  
  28. </declare-styleable>  
<declare-styleable name="Toolbar">
    <attr format="reference" name="titleTextAppearance"/>
    <attr format="reference" name="subtitleTextAppearance"/>
    <attr name="title"/>
    <attr name="subtitle"/>
    <attr name="android:gravity"/>
    <attr format="dimension" name="titleMargins"/>
    <attr format="dimension" name="titleMarginStart"/>
    <attr format="dimension" name="titleMarginEnd"/>
    <attr format="dimension" name="titleMarginTop"/>
    <attr format="dimension" name="titleMarginBottom"/>
    <attr name="contentInsetStart"/>
    <attr name="contentInsetEnd"/>
    <attr name="contentInsetLeft"/>
    <attr name="contentInsetRight"/>
    <attr format="dimension" name="maxButtonHeight"/>
    <attr format="reference" name="collapseIcon"/>
    <attr format="string" name="collapseContentDescription"/>
    <attr name="Theme"/> <!--這裡可以修改ToolBar除了PopupMenu的所有資訊(如背景色:注意java代碼中的setBackgroundColor這個方法不要用存在bug!!!效果不好,使用這裡的background屬性進行設定) 設定的值可以參考主題ThemeOverlay.AppCompat.Dark.ActionBar-->
    <attr name="popupTheme"/>  <!--這裡隻能修改由ToolBar建立的彈出菜單,而對于自己通過建立PopupMenu對象顯示的隻能通過對context設定對應的主題進行設定,設定的值可以參考ThemeOverlay.AppCompat.Light-->
    <attr format="reference" name="navigationIcon"/>
    <attr format="string" name="navigationContentDescription"/>
    <attr name="android:minHeight"/>
    <attr name="logo"/>
    <attr format="string" name="logoDescription"/>
    <attr format="color" name="titleTextColor"/>
    <attr format="color" name="subtitleTextColor"/>
</declare-styleable>           

深入分析:

public class Toolbar extends ViewGroup Toolbar()@Toolbar.class

[java]

view plain copy print ?

  1. public Toolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {  
  2.         super(context, attrs, defStyleAttr);  
  3.         // Need to use getContext() here so that we use the themed context  
  4.         final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,  R.styleable.Toolbar, defStyleAttr, 0);   
  5.         mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);  
  6.         ……//get操作  
  7.         final CharSequence title = a.getText(R.styleable.Toolbar_title);  
  8.         if (!TextUtils.isEmpty(title)) {  
  9.             setTitle(title);  
  10.         }  
  11.         final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle);  
  12.         if (!TextUtils.isEmpty(subtitle)) {  
  13.             setSubtitle(subtitle);  
  14.         }  
  15.         …..//set操作  
  16. }  
public Toolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // Need to use getContext() here so that we use the themed context
        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,  R.styleable.Toolbar, defStyleAttr, 0); 
        mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
        ......//get操作
        final CharSequence title = a.getText(R.styleable.Toolbar_title);
        if (!TextUtils.isEmpty(title)) {
            setTitle(title);
        }

        final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle);
        if (!TextUtils.isEmpty(subtitle)) {
            setSubtitle(subtitle);
        }
        .....//set操作
}           

構造器除了調用ViewGroup的構造器之外,還會擷取目前View所屬Context的主題相關的屬性。

onMeasure()@Toolbar.class

[java]

view plain copy print ?

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.         int width = 0;  
  3.         int height = 0;  
  4.         int childState = 0;  
  5.         ………//note1  
  6.         final int measuredWidth = ViewCompat.resolveSizeAndState(  
  7.                 Math.max(width, getSuggestedMinimumWidth()),  
  8.                 widthMeasureSpec, childState & ViewCompat.MEASURED_STATE_MASK);  
  9.         final int measuredHeight = ViewCompat.resolveSizeAndState(  
  10.                 Math.max(height, getSuggestedMinimumHeight()),  
  11.                 heightMeasureSpec, childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);  
  12.         setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);  
  13. }  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;
        int height = 0;
        int childState = 0;
        .........//note1
        final int measuredWidth = ViewCompat.resolveSizeAndState(
                Math.max(width, getSuggestedMinimumWidth()),
                widthMeasureSpec, childState & ViewCompat.MEASURED_STATE_MASK);
        final int measuredHeight = ViewCompat.resolveSizeAndState(
                Math.max(height, getSuggestedMinimumHeight()),
                heightMeasureSpec, childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);

        setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
}           

1、根據Toolbar中子View設定目前Toolbar顯示 高度寬度。 onLayout()@Toolbar.class

[cpp]

view plain copy print ?

  1. protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  2.         final boolean isRtl =  ViewCompat.getLayoutDirection(this) ==  ViewCompat.LAYOUT_DIRECTION_RTL;  
  3.         //Horizontal layout direction of this view is from Right to Left.  
  4.         final int width = getWidth();  
  5.         final int height = getHeight();  
  6.         final int paddingLeft = getPaddingLeft();  
  7.         final int paddingRight = getPaddingRight();  
  8.         final int paddingTop = getPaddingTop();  
  9.         final int paddingBottom = getPaddingBottom();  
  10.         int left = paddingLeft;  
  11.         int right = width - paddingRight;  
  12.         ….  
  13.         if (shouldLayout(mNavButtonView)) {….}  
  14.         if (shouldLayout(mCollapseButtonView)) {….}  
  15.         if (shouldLayout(mMenuView)) {….}  
  16.         ….  
  17.        addCustomViewsWithGravity(mTempViews, Gravity.LEFT);  
  18.         //ArrayList<View> mTempViews = new ArrayList<View>();  
  19.         final int leftViewsCount = mTempViews.size();  
  20.         for (int i = 0; i < leftViewsCount; i++) {  
  21.             left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins,  
  22.                     alignmentHeight);  
  23.         }  
  24.         addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);{…… }   
  25.         addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);{…… }   
  26.         mTempViews.clear();  
  27. }  
protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final boolean isRtl =  ViewCompat.getLayoutDirection(this) ==  ViewCompat.LAYOUT_DIRECTION_RTL;
        //Horizontal layout direction of this view is from Right to Left.
        final int width = getWidth();
        final int height = getHeight();
        final int paddingLeft = getPaddingLeft();
        final int paddingRight = getPaddingRight();
        final int paddingTop = getPaddingTop();
        final int paddingBottom = getPaddingBottom();
        int left = paddingLeft;
        int right = width - paddingRight;
        ....
        if (shouldLayout(mNavButtonView)) {....}
        if (shouldLayout(mCollapseButtonView)) {....}
        if (shouldLayout(mMenuView)) {....}
        ....

       addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
        //ArrayList<View> mTempViews = new ArrayList<View>();
        final int leftViewsCount = mTempViews.size();
        for (int i = 0; i < leftViewsCount; i++) {
            left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins,
                    alignmentHeight);
        }

        addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);{...... } 
        addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);{...... } 
        mTempViews.clear();
}           

方法先對Toolbar中的導航欄、菜單欄、logo和标題等ActionBar中的屬性進行布局。最後才給自己的childView進行布局。

Reference: http://blog.csdn.net/aigestudio/article/details/47090167