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

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

 

其实主要用的就是CoordinatorLayout+Behavior

首先自定义Behavior

import android.animation.Animator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;

/**
 * 作者:yedajiang44
 * 时间 2018-01-11 16:47
 * 说明:自定义Behavior
 */

public class BottomBarBehavior extends CoordinatorLayout.Behavior<View> {
    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();

    private float viewY;//控件距离coordinatorLayout底部距离
    private boolean isAnimate;//动画是否在进行

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

    /**
     * 有嵌套滑动到来了,问下该Behavior是否接受嵌套滑动
     *
     * @param coordinatorLayout 当前的CoordinatorLayout
     * @param child             该Behavior对应的View
     * @param directTargetChild 我的理解是在CoordinateLayout下作为父View,而该View的子类是Tager的那个View,也就是Target的父View),因为我测试用ViewPager包裹了RecycleView后该参数返回Viewpager,如果没有包裹参数返回的是RecycleView
     * @param target            具体嵌套滑动的那个子类
     * @param nestedScrollAxes  支持嵌套滚动轴。水平方向,垂直方向,或者不指定
     * @param type              导致此滚动事件的输入类型
     * @return 是否接受该嵌套滑动
     */

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int nestedScrollAxes, @ViewCompat.NestedScrollType int type) {
        if (child.getVisibility() == View.VISIBLE && viewY == 0) {
            //获取控件距离父布局(coordinatorLayout)底部距离
            viewY = coordinatorLayout.getHeight() - child.getY();
        }

        //ViewCompat是一个兼容类,在android5.0之前的API为了实现新的效果
        //避免出错使用ViewCompat.xxxx方法可以解决出现低版本错误的问题
        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//判断是否竖直滚动
    }


    /**
     * 在嵌套滑动的子View未滑动之前准备滑动的情况  (待修改)
     *
     * @param coordinatorLayout 此行为与关联的视图的父级CoordinatorLayout
     * @param child             该Behavior对应的View
     * @param target            具体嵌套滑动的那个子类
     * @param dx                水平方向嵌套滑动的子View想要变化的距离
     * @param dy                垂直方向嵌套滑动的子View想要变化的距离
     * @param consumed          这个参数要我们在实现这个函数的时候指定,回头告诉子View当前父View消耗的距离 consumed[0] 水平消耗的距离,consumed[1] 垂直消耗的距离 好让子view做出相应的调整
     * @param type              导致此滚动事件的输入类型
     */
    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        //dy大于0是向上滚动 小于0是向下滚动,判断的时候尽量不要判断是否大于等于或者小于等于0,否则可能会影响点击事件
        //System.out.println(dy);
        if (type == ViewCompat.TYPE_TOUCH) {
            if (dy > 20 && !isAnimate && child.getVisibility() == View.VISIBLE) {
                hide(child);
            } else if (dy < 20 && !isAnimate && child.getVisibility() == View.INVISIBLE) {
                show(child);
            }
        }
    }

    //隐藏时的动画
    private void hide(final View view) {
        ViewPropertyAnimator animator = view.animate().translationY(viewY).setInterpolator(INTERPOLATOR).setDuration(500);

        animator.setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                isAnimate = true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                view.setVisibility(View.INVISIBLE);
                isAnimate = false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                show(view);
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        animator.start();
    }

    //显示时的动画
    private void show(final View view) {
        ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(500);
        animator.setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                view.setVisibility(View.VISIBLE);
                isAnimate = true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                isAnimate = false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                hide(view);
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        animator.start();
    }

}

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

layout布局:

<?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.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:minHeight="?attr/actionBarSize"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/activity_dyeOrder_detail_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways"
            app:navigationIcon="@mipmap/ic_arrow_back_white_24dp"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:title="@string/dyeOrderDetail" />
    </android.support.design.widget.AppBarLayout>


    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/dyeMessageList"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:descendantFocusability="beforeDescendants"
            android:scrollbars="vertical"
            tools:listitem="@layout/recycle_no_dye_message_entry_list" />

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

    <LinearLayout
        android:id="@+id/addLayout"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:gravity="center"
        android:orientation="horizontal"
        android:background="@color/white"
        app:layout_behavior="BottomBarBehavior"
        app:layout_anchor="@id/swipeRefreshLayout"
        app:layout_anchorGravity="bottom|end">
        <TextView
            android:id="@+id/add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="底部菜单" />
    </LinearLayout>

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


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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值