CoordinatorLayout实现底部菜单滑动显示与隐藏

国际惯例:效果图(来自网络,侵删)

CoordinatorLayout实现底部菜单滑动显示与隐藏

其实主要用的就是CoordinatorLayout+Behavior

首先自定义Behavior

[java] view plain copy
  1. import android.animation.Animator;  
  2. import android.content.Context;  
  3. import android.support.annotation.NonNull;  
  4. import android.support.design.widget.CoordinatorLayout;  
  5. import android.support.v4.view.ViewCompat;  
  6. import android.support.v4.view.animation.FastOutSlowInInterpolator;  
  7. import android.util.AttributeSet;  
  8. import android.view.View;  
  9. import android.view.ViewPropertyAnimator;  
  10. import android.view.animation.Interpolator;  
  11.   
  12. /** 
  13.  * 作者:yedajiang44 
  14.  * 时间 2018-01-11 16:47 
  15.  * 说明:自定义Behavior 
  16.  */  
  17.   
  18. public class BottomBarBehavior extends CoordinatorLayout.Behavior<View> {  
  19.     private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();  
  20.   
  21.     private float viewY;//控件距离coordinatorLayout底部距离  
  22.     private boolean isAnimate;//动画是否在进行  
  23.   
  24.     public BottomBarBehavior(Context context, AttributeSet attrs) {  
  25.         super(context, attrs);  
  26.     }  
  27.   
  28.     /** 
  29.      * 有嵌套滑动到来了,问下该Behavior是否接受嵌套滑动 
  30.      * 
  31.      * @param coordinatorLayout 当前的CoordinatorLayout 
  32.      * @param child             该Behavior对应的View 
  33.      * @param directTargetChild 我的理解是在CoordinateLayout下作为父View,而该View的子类是Tager的那个View,也就是Target的父View),因为我测试用ViewPager包裹了RecycleView后该参数返回Viewpager,如果没有包裹参数返回的是RecycleView 
  34.      * @param target            具体嵌套滑动的那个子类 
  35.      * @param nestedScrollAxes  支持嵌套滚动轴。水平方向,垂直方向,或者不指定 
  36.      * @param type              导致此滚动事件的输入类型 
  37.      * @return 是否接受该嵌套滑动 
  38.      */  
  39.   
  40.     @Override  
  41.     public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int nestedScrollAxes, @ViewCompat.NestedScrollType int type) {  
  42.         if (child.getVisibility() == View.VISIBLE && viewY == 0) {  
  43.             //获取控件距离父布局(coordinatorLayout)底部距离  
  44.             viewY = coordinatorLayout.getHeight() - child.getY();  
  45.         }  
  46.   
  47.         //ViewCompat是一个兼容类,在android5.0之前的API为了实现新的效果  
  48.         //避免出错使用ViewCompat.xxxx方法可以解决出现低版本错误的问题  
  49.         return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//判断是否竖直滚动  
  50.     }  
  51.   
  52.   
  53.     /** 
  54.      * 在嵌套滑动的子View未滑动之前准备滑动的情况  (待修改) 
  55.      * 
  56.      * @param coordinatorLayout 此行为与关联的视图的父级CoordinatorLayout 
  57.      * @param child             该Behavior对应的View 
  58.      * @param target            具体嵌套滑动的那个子类 
  59.      * @param dx                水平方向嵌套滑动的子View想要变化的距离 
  60.      * @param dy                垂直方向嵌套滑动的子View想要变化的距离 
  61.      * @param consumed          这个参数要我们在实现这个函数的时候指定,回头告诉子View当前父View消耗的距离 consumed[0] 水平消耗的距离,consumed[1] 垂直消耗的距离 好让子view做出相应的调整 
  62.      * @param type              导致此滚动事件的输入类型 
  63.      */  
  64.     @Override  
  65.     public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {  
  66.         super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);  
  67.         //dy大于0是向上滚动 小于0是向下滚动,判断的时候尽量不要判断是否大于等于或者小于等于0,否则可能会影响点击事件  
  68.         //System.out.println(dy);  
  69.         if (type == ViewCompat.TYPE_TOUCH) {  
  70.             if (dy > 20 && !isAnimate && child.getVisibility() == View.VISIBLE) {  
  71.                 hide(child);  
  72.             } else if (dy < 20 && !isAnimate && child.getVisibility() == View.INVISIBLE) {  
  73.                 show(child);  
  74.             }  
  75.         }  
  76.     }  
  77.   
  78.     //隐藏时的动画  
  79.     private void hide(final View view) {  
  80.         ViewPropertyAnimator animator = view.animate().translationY(viewY).setInterpolator(INTERPOLATOR).setDuration(500);  
  81.   
  82.         animator.setListener(new Animator.AnimatorListener() {  
  83.             @Override  
  84.             public void onAnimationStart(Animator animator) {  
  85.                 isAnimate = true;  
  86.             }  
  87.   
  88.             @Override  
  89.             public void onAnimationEnd(Animator animator) {  
  90.                 view.setVisibility(View.INVISIBLE);  
  91.                 isAnimate = false;  
  92.             }  
  93.   
  94.             @Override  
  95.             public void onAnimationCancel(Animator animator) {  
  96.                 show(view);  
  97.             }  
  98.   
  99.             @Override  
  100.             public void onAnimationRepeat(Animator animator) {  
  101.             }  
  102.         });  
  103.         animator.start();  
  104.     }  
  105.   
  106.     //显示时的动画  
  107.     private void show(final View view) {  
  108.         ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(500);  
  109.         animator.setListener(new Animator.AnimatorListener() {  
  110.             @Override  
  111.             public void onAnimationStart(Animator animator) {  
  112.                 view.setVisibility(View.VISIBLE);  
  113.                 isAnimate = true;  
  114.             }  
  115.   
  116.             @Override  
  117.             public void onAnimationEnd(Animator animator) {  
  118.                 isAnimate = false;  
  119.             }  
  120.   
  121.             @Override  
  122.             public void onAnimationCancel(Animator animator) {  
  123.                 hide(view);  
  124.             }  
  125.   
  126.             @Override  
  127.             public void onAnimationRepeat(Animator animator) {  
  128.             }  
  129.         });  
  130.         animator.start();  
  131.     }  
  132.   
  133. }  

自定义好了Behavior之后就需要在layout布局文件里使用了

layout布局:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent">  
  7.   
  8.     <android.support.design.widget.AppBarLayout  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:fitsSystemWindows="true"  
  12.         android:minHeight="?attr/actionBarSize"  
  13.         android:theme="@style/AppTheme.AppBarOverlay">  
  14.   
  15.         <android.support.v7.widget.Toolbar  
  16.             android:id="@+id/activity_dyeOrder_detail_toolbar"  
  17.             android:layout_width="match_parent"  
  18.             android:layout_height="?attr/actionBarSize"  
  19.             android:background="?attr/colorPrimary"  
  20.             android:minHeight="?attr/actionBarSize"  
  21.             app:layout_scrollFlags="scroll|enterAlways"  
  22.             app:navigationIcon="@mipmap/ic_arrow_back_white_24dp"  
  23.             app:popupTheme="@style/AppTheme.PopupOverlay"  
  24.             app:title="@string/dyeOrderDetail" />  
  25.     </android.support.design.widget.AppBarLayout>  
  26.   
  27.   
  28.     <android.support.v4.widget.SwipeRefreshLayout  
  29.         android:id="@+id/swipeRefreshLayout"  
  30.         android:layout_width="match_parent"  
  31.         android:layout_height="match_parent"  
  32.         app:layout_behavior="@string/appbar_scrolling_view_behavior">  
  33.   
  34.         <android.support.v7.widget.RecyclerView  
  35.             android:id="@+id/dyeMessageList"  
  36.             android:layout_width="match_parent"  
  37.             android:layout_height="match_parent"  
  38.             android:descendantFocusability="beforeDescendants"  
  39.             android:scrollbars="vertical"  
  40.             tools:listitem="@layout/recycle_no_dye_message_entry_list" />  
  41.   
  42.     </android.support.v4.widget.SwipeRefreshLayout>  
  43.   
  44.     <LinearLayout  
  45.         android:id="@+id/addLayout"  
  46.         android:layout_width="match_parent"  
  47.         android:layout_height="?attr/actionBarSize"  
  48.         android:gravity="center"  
  49.         android:orientation="horizontal"  
  50.         android:background="@color/white"  
  51.         app:layout_behavior="BottomBarBehavior"  
  52.         app:layout_anchor="@id/swipeRefreshLayout"  
  53.         app:layout_anchorGravity="bottom|end">  
  54.         <TextView  
  55.             android:id="@+id/add"  
  56.             android:layout_width="wrap_content"  
  57.             android:layout_height="wrap_content"  
  58.             android:layout_gravity="center_vertical"  
  59.             android:text="底部菜单" />  
  60.     </LinearLayout>  
  61.   
  62. </android.support.design.widget.CoordinatorLayout>  

需要注意的是app:layout_behavior="BottomBarBehavior"中的BottomBarBehavior如果不在根目录需要加上包名