一、BottomNavigationBehavior
动画效果是会跟着屏幕一起滚动,上滑时向下滚动移除屏幕,下滑向上滚动显示,适用于底部切换部分。
效果图:
如图,底部很好的移除了屏幕,悬浮按钮由于有一定的间距还留有一部分,可以通过修改动画或者单独给悬浮按钮设置一个 Behavior。
BottomNavigationBehavior:
/*** Created by chenxz on 2017/11/25.* 下滑一起下滑,下滑到屏幕外就不可见了,上滑一起上滑*/public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<View> {private ObjectAnimator outAnimator, inAnimator;public BottomNavigationBehavior(Context context, AttributeSet attrs) {super(context, attrs);}// 垂直滑动@Overridepublic boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;}@Overridepublic 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() * 2);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() * 2, 0);inAnimator.setDuration(200);}if (!inAnimator.isRunning() && child.getTranslationY() >= child.getHeight()) {inAnimator.start();}}}}
使用的 xml 布局:
<?xml version="1.0" encoding="utf-8"?><androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"><com.google.android.material.appbar.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><androidx.appcompat.widget.Toolbarandroid:id="@+id/tb_tb_scroll_tb"android:layout_width="match_parent"android:layout_height="wrap_content"app:navigationIcon="@mipmap/ic_navigation_back_white"app:title="toolbar滚动"app:titleTextColor="@color/white"android:background="@color/blue_74D3FF"app:layout_scrollFlags="scroll|enterAlways|snap"/></com.google.android.material.appbar.AppBarLayout><include layout="@layout/content_scrolling"/><!-- <androidx.core.widget.NestedScrollView--><!-- android:layout_width="match_parent"--><!-- android:layout_height="match_parent"--><!-- app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">--><!-- <TextView--><!-- android:layout_width="wrap_content"--><!-- android:layout_height="wrap_content"--><!-- android:layout_margin="@dimen/m12"--><!-- android:text="@string/large_text" />--><!-- </androidx.core.widget.NestedScrollView>--><!-- 加个底部滑动隐藏,适用于底部有控件的情况,上滑显示,--><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:layout_gravity="bottom"android:background="@color/yellow_FF9B52"app:layout_behavior="@string/bottom_navigation_behavior"></RelativeLayout><!-- 悬浮按钮--><com.google.android.material.floatingactionbutton.FloatingActionButtonandroid:id="@+id/fab_tb_scroll_menu"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="end|bottom"android:layout_marginEnd="@dimen/m12"android:layout_marginBottom="60dp"android:src="@drawable/ic_cloud"app:layout_behavior="@string/bottom_navigation_behavior"/></androidx.coordinatorlayout.widget.CoordinatorLayout>
strings,将文件放在strings 里,方便以后对 Behavior 修改:
<string name="scale_up_show_behavior">com.kiwilss.xview.design.behavior.ScaleUpShowBehavior</string><string name="bottom_navigation_behavior">com.kiwilss.xview.design.behavior.BottomNavigationBehavior</string>
二、ScaleDownShowBehavior
FAB 行为控制器,下滑直接消失,上滑缩放出现。效果图:
代码:
/*** Created by chenxz on 2018/5/13.** FAB 行为控制器,下滑直接消失,上滑缩放出现*/class ScaleDownShowBehavior : FloatingActionButton.Behavior {constructor(context: Context, attrs: AttributeSet) : super(context, attrs)override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,child: FloatingActionButton,directTargetChild: View,target: View,axes: Int,type: Int): Boolean {return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)}@SuppressLint("RestrictedApi")override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)if (dyConsumed > 0 && child.visibility == View.VISIBLE) {child.visibility = View.INVISIBLE} else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {child.show()}}}
三、ScaleUpShowBehavior
FloatingActionButton上滑缩小隐藏,上滑放大显示,使用于返回顶部等
效果图:
代码:
/*** @author : Lss Administrator* @FileName: ScaleUpShowBehavior* @e-mail : kiwilss@163.com* @time : 2020/8/17* @desc : {FloatingActionButton上滑缩小隐藏,上滑放大显示,使用于返回顶部等}*/public class ScaleUpShowBehavior extends FloatingActionButton.Behavior {public ScaleUpShowBehavior(Context context, AttributeSet attrs) {super();}private boolean isAnimatingOut = false;private boolean isShow = true;@Overridepublic boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,@NonNull FloatingActionButton child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);//return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);}@Overridepublic void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, @NonNull int[] consumed) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed);// if (dyConsumed > 0 && dyUnconsumed == 0) {// System.out.println("上滑中。。。");// }// if (dyConsumed == 0 && dyUnconsumed > 0) {// System.out.println("到边界了还在上滑。。。");// }// if (dyConsumed < 0 && dyUnconsumed == 0) {// System.out.println("下滑中。。。");// }// if (dyConsumed == 0 && dyUnconsumed < 0) {// System.out.println("到边界了,还在下滑。。。");// }// 手指上滑,隐藏FAB// 手指上滑,隐藏FABif ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimatingOut && isShow) {AnimatorUtil.INSTANCE.scaleHide(child, viewPropertyAnimatorListenerHide);} else if (dyConsumed < 0 || dyUnconsumed < 0 && !isAnimatingOut && !isShow) {// 手指下滑,显示FABAnimatorUtil.INSTANCE.scaleShow(child,viewPropertyAnimatorListener);}}ViewPropertyAnimatorListener viewPropertyAnimatorListener = new ViewPropertyAnimatorListener() {@Overridepublic void onAnimationStart(View view) {//view.setVisibility(View.VISIBLE);isAnimatingOut = true;}@Overridepublic void onAnimationEnd(View view) {isAnimatingOut = false;}@Overridepublic void onAnimationCancel(View arg0) {isAnimatingOut = false;}};ViewPropertyAnimatorListener viewPropertyAnimatorListenerHide = new ViewPropertyAnimatorListener() {@Overridepublic void onAnimationStart(View view) {isAnimatingOut = true;}@Overridepublic void onAnimationEnd(View view) {isAnimatingOut = false;//view.setVisibility(View.GONE);}@Overridepublic void onAnimationCancel(View arg0) {isAnimatingOut = false;}};}
四、ScrollAwareFABBehavior
FAB 上滑移出屏幕, 下滑显示,很想知乎首页,效果图:
代码:
/*** Created by chenxz on 2018/5/13.** FAB 上滑隐藏 下滑显示*/class ScrollAwareFABBehavior : FloatingActionButton.Behavior {/*** 是否正在动画*/private var isAnimateIng = false/*** 是否已经显示*/private var isShow = trueconstructor(context: Context, attrs: AttributeSet) : super()override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,child: FloatingActionButton,directTargetChild: View,target: View,axes: Int,type: Int): Boolean {return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)}override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)// 手指上滑,隐藏FABif ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimateIng && isShow) {AnimatorUtil.translateHide(child, object : StateListener() {override fun onAnimationStart(view: View) {super.onAnimationStart(view)isShow = false}})} else if (dyConsumed < 0 || dyUnconsumed < 0 && !isAnimateIng && !isShow) {// 手指下滑,显示FABAnimatorUtil.translateShow(child, object : StateListener() {override fun onAnimationStart(view: View) {super.onAnimationStart(view)isShow = true}})}}internal open inner class StateListener : ViewPropertyAnimatorListener {override fun onAnimationStart(view: View) {isAnimateIng = true}override fun onAnimationEnd(view: View) {isAnimateIng = false}override fun onAnimationCancel(view: View) {isAnimateIng = false}}}
