CoordinatorLayout 學習筆記

CoordinatorLayout 是 support:design 提供的一個重要布局,雖然由于產品設計的原因,我在正式項目中還沒有機會使用到, 不過它提供了一些非常不錯的效果,值得記錄一下.

Android中處理事件分發還是挺麻煩的,需要從頂層開始,層層分發,攔截,響應.特別是涉及到多層嵌套的時候,需要判斷什么時候攔截,攔截后怎么處理;什么時候放行...

CoordinatorLayout 可以用于調度協調子布局,實現聯動效果.使用它,可以簡化事件的處理.下面是 CoordinatorLayout 的一些常用方式.

CoordinatorLayout 和 FloatingActionButton

FloatingActionButton就是一個按鈕,不過可以設置一些5毛特效.


<!-- 
      app:backgroundTint 默認填充色 
      app:rippleColor    點擊時填充色 
      app:elevation      默認高度(高度越高,陰影越大)   
      app:pressedTranslationZ 點擊時高度
      app:layout_anchor  依賴目標 
      app:layout_anchorGravity 相對依賴目標的位置 
 -->

Snackbar是從底部彈出的,當它顯示的時候,如果遮住了按鈕,體驗就不太好,CoordinatorLayout 就可以解決這個問題,當使用 CoordinatorLayout 作為容器時,如果顯示Snackbar,FloatingActionButton會有一個向上移動的效果

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
   xmlns:android="http://schemas.android.com/apk/res/android"    
   xmlns:app="http://schemas.android.com/apk/res-auto"    
   xmlns:tools="http://schemas.android.com/tools"    
   android:layout_width="match_parent"    
   android:layout_height="match_parent"    
   android:fitsSystemWindows="true">    
  
   <android.support.v4.widget.NestedScrollView        
       android:id="@+id/scroll"        
       android:layout_width="match_parent"        
       android:layout_height="match_parent"        
       app:layout_behavior="@string/appbar_scrolling_view_behavior">        

       <TextView            
           android:layout_width="wrap_content"            
           android:layout_height="wrap_content"            
           android:layout_margin="@dimen/text_margin"            
           android:text="@string/large_text" />    

   </android.support.v4.widget.NestedScrollView>    
   <android.support.design.widget.FloatingActionButton        
      android:id="@+id/fab"        
      android:layout_width="wrap_content"        
      android:layout_height="wrap_content"        
      app:layout_behavior="com.heihei.hehe.coordinatorlayout.behavior.FloatButtonBehavior"        
      app:layout_anchor="@id/scroll"        
      app:layout_anchorGravity="bottom|end"         
      app:backgroundTint="#fff000"        
      app:rippleColor="@color/colorAccent"        
      app:elevation="6dp"        
      app:pressedTranslationZ="12dp"        
      android:layout_margin="@dimen/fab_margin"        
      app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

關于FloatingActionButton,還可以實現一些更好的特效,不過需要涉及到 CoordinatorLayout 的原理,放在靠后一些的地方.

CoordinatorLayout 和 AppBarLayout

CoordinatorLayout 和 AppBarLayout一起使用,可以實現的效果有很多

Toolbar的快速返回
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
   xmlns:android="http://schemas.android.com/apk/res/android"    
   xmlns:app="http://schemas.android.com/apk/res-auto"    
   xmlns:tools="http://schemas.android.com/tools"    
   android:layout_width="match_parent"    
   android:layout_height="match_parent"    
   android:fitsSystemWindows="true">    

   <android.support.design.widget.AppBarLayout    
       android:id="@+id/app_bar"    
       android:layout_width="match_parent"    
       android:layout_height="wrap_content"    
       android:theme="@style/AppTheme.AppBarOverlay">    
      
      <android.support.v7.widget.Toolbar        
          android:id="@+id/toolbar"        
          app:layout_scrollFlags="scroll|enterAlways"        
          android:layout_width="match_parent"        
          android:layout_height="?attr/actionBarSize"        
          app:navigationIcon="?attr/homeAsUpIndicator"        
          app:popupTheme="@style/AppTheme.PopupOverlay" />

   </android.support.design.widget.AppBarLayout>
  
   <android.support.v4.widget.NestedScrollView        
       android:id="@+id/scroll"        
       android:layout_width="match_parent"        
       android:layout_height="match_parent"        
       app:layout_behavior="@string/appbar_scrolling_view_behavior">        

       <TextView            
           android:layout_width="wrap_content"            
           android:layout_height="wrap_content"            
           android:layout_margin="@dimen/text_margin"            
           android:text="@string/large_text" />    

   </android.support.v4.widget.NestedScrollView>   

</android.support.design.widget.CoordinatorLayout>

內容上劃時,隱藏toolbar,下劃時,顯示toolbar,實現這個效果的關鍵在于

  1. 給滾動視圖添加屬性
    // 只有添加了該屬性,才能讓CoordinatorLayout 響應子視圖的滾動事件
    // 注: 滾動視圖必須要實現 NestedScrollingChild
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
  2. toolbar放在 AppBarLayout 里面(暫時可以認為,只有AppBarLayout 里面的控件,才能響應滑動)
  3. 個toolbar添加屬性
    app:layout_scrollFlags="scroll|..."

關于 app:layout_scrollFlags 還可以設置一些其它的值,實現的效果也有區別

scroll   
    這個值必須有,沒有這個值,控件會固定在屏幕上,不響應任何事件
snap    
    設置這個值后,toolbar不會停止在中間狀態,結束狀態要么完全顯示,要么完全隱藏
enterAlways 
    向上滾動,隱藏該控件;向下的滾動,顯示該控件
enterAlwaysCollapsed
    向上滾動,隱藏該控件;
    向下滑動:
        a.沒有設置 minHeight,當滾動視圖到達頂部,再顯示該控件 
        b.設置 minHeight,先已最小高度出現,等滾動視圖到達頂部,再顯示該控件(同時需要設置 enterAlways  才生效)
 exitUntilCollapsed
    滾動視圖向上滾動時,該控件會折疊在頂部,這個在后面再具體說明

toolbar 搭配 tablayout 使用

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
   xmlns:android="http://schemas.android.com/apk/res/android"    
   xmlns:app="http://schemas.android.com/apk/res-auto"    
   xmlns:tools="http://schemas.android.com/tools"    
   android:layout_width="match_parent"    
   android:layout_height="match_parent"    
   android:fitsSystemWindows="true">    

   <android.support.design.widget.AppBarLayout    
       android:id="@+id/app_bar"    
       android:layout_width="match_parent"    
       android:layout_height="wrap_content"    
       android:theme="@style/AppTheme.AppBarOverlay">    
      
      <android.support.v7.widget.Toolbar        
          android:id="@+id/toolbar"        
          app:layout_scrollFlags="scroll|enterAlways"        
          android:layout_width="match_parent"        
          android:layout_height="?attr/actionBarSize"        
          app:navigationIcon="?attr/homeAsUpIndicator"        
          app:popupTheme="@style/AppTheme.PopupOverlay" />

      <android.support.design.widget.TabLayout    
          android:id="@+id/tabs"    
          android:layout_width="match_parent"    
          android:layout_height="wrap_content"    
          app:tabMode="scrollable"    
          app:tabIndicatorHeight="3dp"     
          app:tabTextColor="@color/color_ffffff"    
          app:tabSelectedTextColor="@color/colorAccent"    
          app:tabIndicatorColor="@color/colorAccent"/>

   </android.support.design.widget.AppBarLayout>
  
   <android.support.v4.widget.NestedScrollView        
       android:id="@+id/scroll"        
       android:layout_width="match_parent"        
       android:layout_height="match_parent"        
       app:layout_behavior="@string/appbar_scrolling_view_behavior">        

       <TextView            
           android:layout_width="wrap_content"            
           android:layout_height="wrap_content"            
           android:layout_margin="@dimen/text_margin"            
           android:text="@string/large_text" />    

   </android.support.v4.widget.NestedScrollView>   

</android.support.design.widget.CoordinatorLayout>

順便解釋下TabLayout的一些屬性

  app:tabMode                模式,有兩個值:scrollable(可滾動); fixed(固定的)
  app:tabIndicatorHeight     指示滑塊的高度
  app:tabTextColor           文字的顏色
  app:tabSelectedTextColor   文字選中狀態的顏色
  app:tabIndicatorColor      指示滑塊的顏色

app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways"

app:layout_scrollFlags="scroll|exitUntilCollapsed"

exitUntilCollapsed一般結合CollapsingToolbarLayout使用

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
   xmlns:android="http://schemas.android.com/apk/res/android"    
   xmlns:app="http://schemas.android.com/apk/res-auto"    
   xmlns:tools="http://schemas.android.com/tools"    
   android:layout_width="match_parent"    
   android:layout_height="match_parent"    
   android:fitsSystemWindows="true">    

   <android.support.design.widget.AppBarLayout    
       android:id="@+id/app_bar"    
       android:layout_width="match_parent"    
       android:layout_height="250dp"
       android:fitsSystemWindows="true"  
       android:theme="@style/AppTheme.AppBarOverlay">    
      
      <android.support.design.widget.CollapsingToolbarLayout    
          android:id="@+id/toolbar_layout"    
          android:layout_width="match_parent"    
          android:layout_height="match_parent"   
          android:minHeight="?attr/actionBarSize"    
          android:fitsSystemWindows="true"    
          app:contentScrim="?attr/colorPrimary"    
          app:statusBarScrim="?attr/colorAccent"    
          app:title="title"   
          app:collapsedTitleGravity="left"    
          app:expandedTitleGravity="center_horizontal|bottom"    
          app:layout_scrollFlags="scroll|exitUntilCollapsed">    

          <ImageView        
             android:src="@mipmap/icon_bg_mine"        
             android:layout_width="match_parent"        
             android:layout_height="match_parent"        
             android:scaleType="centerCrop"        
             app:layout_collapseMode="parallax"/>    

          <android.support.v7.widget.Toolbar        
             android:id="@+id/toolbar"        
             app:layout_collapseMode="pin"        
             android:layout_width="match_parent"        
             android:layout_height="?attr/actionBarSize"        
             app:navigationIcon="?attr/homeAsUpIndicator"        
             app:popupTheme="@style/AppTheme.PopupOverlay" />

      </android.support.design.widget.CollapsingToolbarLayout>

   </android.support.design.widget.AppBarLayout>
  
   <android.support.v4.widget.NestedScrollView        
       android:id="@+id/scroll"        
       android:layout_width="match_parent"        
       android:layout_height="match_parent"        
       app:layout_behavior="@string/appbar_scrolling_view_behavior">        

       <TextView            
           android:layout_width="wrap_content"            
           android:layout_height="wrap_content"            
           android:layout_margin="@dimen/text_margin"            
           android:text="@string/large_text" />    

   </android.support.v4.widget.NestedScrollView>   

</android.support.design.widget.CoordinatorLayout>

上面的例子中,CollapsingToolbarLayout在滾動視圖上滑時,會逐漸收縮折疊在屏幕上方(折疊高度受最小高度影響). 同時 CollapsingToolbarLayout 的子視圖可以設置折疊模式

  // 折疊模式 
  app:layout_collapseMode      
  有兩個值:
       parallax ->  視差模式,就是上面的圖片的變化效果
       pin      ->  固定模式,在折疊的時候最后固定在頂端

  // 視差效果
  app:layout_collapseParallaxMultiplier   
  范圍[0.0,1.0],值越大視差越大

CollapsingToolbarLayout 中使用到的幾個屬性也解釋一下:

  //折疊后的背景色  -> setContentScrim(Drawable)
  app:contentScrim="?attr/colorPrimary"   
  // 必須設置透明狀態欄才有效  -> setStatusBarScrim(Drawable)     
  app:statusBarScrim="?attr/colorAccent"    
  // 標題  
  app:title="title"
  // 折疊后的標題位置
  app:collapsedTitleGravity="left"
  // 打開時的標題位置
  app:expandedTitleGravity="center_horizontal|bottom"

PS: AppbarLayout 的展開和關閉是可以通過代碼控制的

 appbarLayout.setExpanded(true,false);
CoordinatorLayout 和 BottomSheet

通過 CoordinatorLayout 也可以實現底部彈窗的效果,并且效果更好

  <android.support.v4.widget.NestedScrollView    
     android:id="@+id/scroll"    android:layout_width="match_parent"    
     android:layout_height="300dp"    
     app:behavior_peekHeight="0dp"    
     app:behavior_hideable="true"    
     app:layout_behavior="@string/bottom_sheet_behavior">    

    <TextView        
       android:layout_width="wrap_content"        
       android:layout_height="wrap_content"        
       android:layout_margin="@dimen/text_margin"        
       android:text="@string/large_text" />

  </android.support.v4.widget.NestedScrollView>

可以看到,在 CoordinatorLayout 中,只要給某個視圖指定屬性

   app:layout_behavior="@string/bottom_sheet_behavior"

就可以將該視圖變為底部菜單的形式,同時可以通過其它幾個屬性改變菜單的規則

  // 關閉時的高度
  app:behavior_peekHeight="0dp"    
  // 是否可以完全隱藏,如果指定為 false,那么將最少已上面的高度顯示
  app:behavior_hideable="true"   

代碼中控制

  // 初始化
  sheetBehavior = BottomSheetBehavior.from(findViewById(R.id.scroll));

  // 打開
  sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
  //關閉
  sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
  //隱藏
  sheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
 // 狀態監聽
 sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {    
     @Override    
     public void onStateChanged(@NonNull View bottomSheet, int newState) {        
        // 狀態改變時回調       
        if(newState == BottomSheetBehavior.STATE_EXPANDED){            
            Toast.makeText(bottomSheet.getContext(),"打開了",Toast.LENGTH_SHORT).show();       
        }else if(newState == BottomSheetBehavior.STATE_COLLAPSED){            
            Toast.makeText(bottomSheet.getContext(),"關閉了",Toast.LENGTH_SHORT).show();        
        }else if(newState == BottomSheetBehavior.STATE_HIDDEN){            
            Toast.makeText(bottomSheet.getContext(),"隱藏了",Toast.LENGTH_SHORT).show();       
        }    
      }    

      @Override    
      public void onSlide(@NonNull View bottomSheet, float slideOffset) {        
          // 拖動時回調    
      }
 });
BottomSheetDialog

BottomSheetDialog 也是一種從底部彈起的對話框,使用起來和 CoordinatorLayout 沒什么關系,這里也一起介紹

    // 直接通過構造方法初始化
    BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(v.getContext());
    //設置內容
    bottomSheetDialog.setContentView(R.layout.content_scrolling);
    //顯示
    bottomSheetDialog.show();

常規的一些用法到這里差不多了. 那么為什么 CoordinatorLayout 可以實現這些效果? 因為在上面我們好像并沒有寫什么代碼,就是簡單的謝謝布局,設置一下屬性就可以了.

其實CoordinatorLayout自己并不控制View,所有的控制權都在Behavior. Behavior是 CoordinatorLayout 的內部內,是個抽象類. 它的子視圖通過實現Behavior,然后CoordinatorLayout就可以進行協同管理.

前面我們使用了AppBarLayout 和 FloatingActionButton ,可以去源碼里簡單的看一下

  @CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
  public class AppBarLayout extends LinearLayout {

  ...
  
  @CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
  public class FloatingActionButton extends VisibilityAwareImageButton {

   ...

可以看到,這兩個控件都使用了Behavior,使用 Behavior的方式也有多種:

  • 注解綁定Behavior,當我們使用自定義控件的時候,就可以像上面一樣,直接通過注解指定 Behavior.
  • 在XML中綁定Behavior
    app:layout_behavior="Behavior的包名"
  • 代碼綁定Behavior
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
    params.setBehavior(behavior);

同時,也可以通過自定義Behavior實現一些特殊的效果

// 如果該Behavior只想給某種控件使用,可以通過泛型控制, 當然也可以不指定,那么任何控件都可以使用
public class MyBehavior<T> extends CoordinatorLayout.Behavior {    

  // 構造方法必須要寫,因為Behavior最終都是通過反射此構造方法初始化    
  // 可以帶有自定義屬性    
  public MyBehavior(Context context, AttributeSet attrs) {        
     super(context, attrs);   
  }    

  // 視圖依賴(想想觀察者模式),在這里可以指定具體的對象,也可以指定一個范圍    
  // 比如這里指定了,只觀察 AppBarLayout 的變化    
  @Override    
  public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {        
     return dependency instanceof AppBarLayout;    
  }    

  /**     
   * 依賴的對象發生了變化(觀察者 onNext...),可以在這里做出相應的處理,比如位置改變,大小變化等     
   * @param child      使用此 Behavior 的控件     
   * @param dependency 觀察的控件     
   */    
   @Override    
   public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {        
      return true;    
   }    

 /**************************以下是滑動事件的相關方法(無需聲明依賴,不受依賴影響)*************************/    

   /**     
    * (嵌套)滾動事件開始前     
    * 通過返回值表示要不要響應本次滑動,只有這里返回true,后面的響應方法才會執行    
    * 比如這里,表示只響應垂直方向的滑動     
    * @param child             自己     
    * @param directTargetChild 發起滑動事件的控件     
    * @param target     
    */    
    @Override    
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {        
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;    
     }   

     /**     
      * (嵌套)滾動事件開始后,滾動視圖獲得滾動事件前     
      * @param dy        垂直方向滑動增量    
      * @param consumed  長度為二 , 水平和垂直方向消耗掉的滾動     
      */    
     @Override    
     public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {        
         //dy大于0是向上滾動 小于0是向下滾動    
     }   

     /**     
      * 滾動視圖獲得(嵌套)滾動事件后     
      * @param dyConsumed     豎直方向上滑動被消耗了多少     
      * @param dyUnconsumed   未消耗的     
      */    
      @Override    
      public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {       
          if (dyConsumed > 0 && dyUnconsumed == 0) {            
              // 上滑       
          }       
          if (dyConsumed == 0 && dyUnconsumed > 0) {           
             // 到邊了, 還在上滑        
          }       
          if (dyConsumed < 0 && dyUnconsumed == 0) {           
             // 下滑       
          }        
          if (dyConsumed == 0 && dyUnconsumed < 0) {            
             // 到邊了, 還在下滑        
          }    
       }    

       // (嵌套)滾動事件結束后    
       @Override    
       public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {   
       }    

       // 快速滑動開始前    
       @Override    
       public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {        return false;   
       }    

       // 快速滑動    
       @Override    
       public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {        return false;    
       }
 }

自定義Behavior的套路就在上面,注釋很詳細了,下面是幾個具體的例子

1.FloatingActionButton 在向上滾動是隱藏,向下滾動時出現

public class FloatButtonBehavior extends FloatingActionButton.Behavior {    
 
  // 構造方法必須有,使用的時候,會通過反射調用該構造方法實例化, 如果沒有,會保錯    
  public FloatButtonBehavior(Context context, AttributeSet attrs) {        
      super();    
  }    

  @Override    
  public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,  final View directTargetChild, final View target, final int nestedScrollAxes) {        
    // Ensure we react to vertical scrolling        
    return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);    
  }    

  //上滑隱藏,下滑顯示    
  @Override    
  public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {        
      super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,dyUnconsumed);        
      if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {            
            child.hide();        
      } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {            
            child.show();        
      }    
   }
}

2.底部菜單的上滑隱藏

 public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<View> {    

    private ObjectAnimator outAnimator,inAnimator;    

    public BottomNavigationBehavior(Context context, AttributeSet attrs) {        
        super(context, attrs);   
    }    

    // 垂直滑動    
    @Override    
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {        
       return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;    
    }    

    @Override    
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {        
        if(dy > 0){//上滑隱藏           
            if(outAnimator == null){                
                outAnimator = ObjectAnimator.ofFloat(child,"translationY",0,child.getHeight());                
                outAnimator.setDuration(200);            
            }            
            if(!outAnimator.isRunning() && child.getTranslationY() <= 0){                
                outAnimator.start();            
            }        
         }else if(dy < 0){//下滑顯示            
           if(inAnimator == null){               
               inAnimator = ObjectAnimator.ofFloat(child,"translationY",child.getHeight(),0);                
               inAnimator.setDuration(200);            
            }            
            if(!inAnimator.isRunning() && child.getTranslationY() >= child.getHeight()){               
               inAnimator.start();            
            }        
          }    
     }
 }

上面的例子用到了 support:design:25.0.0 里的一個新控件 BottomNavigationView

使用方式如下:

  <!-- 
     app:itemBackground  按鈕背景
     app:itemIconTint         圖標顏色
     app:itemTextColor      文字顏色
     app:menu                   菜單
  -->
  <android.support.design.widget.BottomNavigationView    
      android:id="@+id/navigation"    
      android:layout_width="match_parent"    
      android:layout_height="wrap_content"    
      android:layout_gravity="bottom"    
      app:layout_behavior="com.heihei.hehe.coordinatorlayout.behavior.BottomNavigationBehavior"    
      app:itemBackground="@color/color_1ec859"    
      app:itemIconTint="@drawable/tab_text_color_selector"    
      app:itemTextColor="@drawable/tab_text_color_selector"    
      app:menu="@menu/menu_navigation"/>

menu:

 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android">    
    <item        
      android:id="@+id/item1"        
      android:checked="true"        
      android:icon="@android:drawable/stat_notify_chat"        
      android:title="Message"/>    

   <item        
      android:id="@+id/item2"        
      android:icon="@android:drawable/stat_notify_error"        
      android:title="Call"/>    

   <item        
      android:id="@+id/item3"        
      android:icon="@android:drawable/stat_notify_more"        
      android:title="Contact"/>    
 
   <item        
      android:id="@+id/item4"        
      android:icon="@android:drawable/stat_notify_sync"        
      android:title="aaa"/>

 </menu>

代碼中設置:

  navigationView = (BottomNavigationView) findViewById(R.id.navigation);
  navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {    

     @Override    
     public boolean onNavigationItemSelected(@NonNull MenuItem item) {        
          switch (item.getItemId()){            
              case R.id.item1:                
                 navigationView.setItemBackgroundResource(R.color.color_1ec859);                
                 break;            
              case R.id.item2:                
                 navigationView.setItemBackgroundResource(R.color.color_3b93eb);                
                 break;            
              case R.id.item3:                
                 navigationView.setItemBackgroundResource(R.color.color_ffa973);                
                break;            
              case R.id.item4:                
                 navigationView.setItemBackgroundResource(R.color.color_ffbc00);                
               break;       
            }        
           Toast.makeText(BottomNavigationActivity.this, item.getTitle(), Toast.LENGTH_SHORT).show();        
           return false;    
      }
   });

3.頭像動畫

 public class HeaderImageBehavior extends CoordinatorLayout.Behavior {    

     private float distanceY;    

     public HeaderImageBehavior(Context context, AttributeSet attrs) {        
          super(context, attrs);        
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HeadBehavior);        
          distanceY = a.getDimension(R.styleable.HeadBehavior_openHeight,dip2px(context,250))//750        -a.getDimension(R.styleable.HeadBehavior_closeHeight,dip2px(context,56));//168       
          a.recycle();   
      }    

      @Override    
      public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {        
         return dependency instanceof AppBarLayout;    
      }        

      @Override    
      public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {        
         float p = Math.abs(dependency.getY())*1f/distanceY;        child.setScaleX(1- p/2);       
        child.setScaleY(1- p/2);        
        child.setTranslationX(-child.getLeft()*p);        
        return true;    
      }    

      private int dip2px(Context context, float dpValue) {       
         final float scale = context.getResources().getDisplayMetrics().density;        
         return (int) (dpValue * scale + 0.5f);   
      }
   }

CoordinatorLayout 還可以實現更復雜的效果,能力有限,就整理到這里了

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

推薦閱讀更多精彩內容