CoordinatorLayout 学习笔记

作者: 四月一号 | 来源:发表于2016-10-27 20:26 被阅读1343次

    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 还可以实现更复杂的效果,能力有限,就整理到这里了

    相关文章

      网友评论

      • laer_L:真心不错,只是BottomSheetBehavior这个没搞懂是干嘛的,我已经把你的dome下载下来了,估计看看就能懂
      • 605094d76408:正好用的上,写的很好,大赞。
      • Android小人:关键是app:layout_behavior这个东西怎么写,所有的关联动画都和这个东西有关系
        四月一号:@Android小人 你是说怎么给控件指定 behavior ,还是什么? 关于指定 behavior 的方式,文章里有总结了三种方式
      • ximencx:写的挺不错的 demo可以下载么 求地址
        四月一号:@ximencx https://github.com/13456961183/CoordinatorLayout
        Demo在这里, 其实代码在文中都贴出来了

      本文标题:CoordinatorLayout 学习笔记

      本文链接:https://www.haomeiwen.com/subject/xuvjuttx.html