之前写过一篇FAB按钮的隐藏显示,FloatingActionButton在RecycleView中滑动隐藏显示,它是通过监听RecycleView的滑动实现的,不过Google官方并没有推荐这种方式,今天看看比较官方的做法通过重写Behavior来实现。
public class FABBehavior extends FloatingActionButton.Behavior {
private boolean visible = true;//是否可见
public FABBehavior(Context context, AttributeSet attrs) {
super();
}
//当观察的RecyclerView发生滑动开始的时候回调的
//axes滑动关联轴,我们现在只关心垂直的滑动
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, 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);
}
@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
if (dyConsumed > 0 && visible) {
visible = false;
animateOut(child);
} else if (dyConsumed < 0 && !visible) {
visible = true;
animateIn(child);
}
}
// FAB隐藏动画
private void animateOut(FloatingActionButton fab) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
fab.animate().translationY(fab.getHeight() + layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();
}
// FAB显示动画
private void animateIn(FloatingActionButton fab) {
fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();
}
}
代码注释中对关键的地方已经注释很清楚了,在不重复说明了,
下面看看界面布局文件
<?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:tooltipText=""
tools:context="com.mtx.floatingactionbutton.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rcv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fcb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:backgroundTint="@color/colorAccent"
android:onClick="onClickFAB"
android:src="@drawable/up"
app:borderWidth="0dp"
app:elevation="10dp"
app:fabSize="normal"
app:layout_anchor="@id/rcv"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="com.mtx.floatingactionbutton.FABBehavior"
app:rippleColor="@color/colorPrimary" />
</android.support.design.widget.CoordinatorLayout>
CoordinatorLayout帮助协调定义在里面的view之间的动画,app:layout_behavior="com.mtx.floatingactionbutton.FABBehavior" 这一行是重点,app:layout_behavior的值为我们自定义的类,ayout_anchor 与 layout_anchorGravity 属性就可以了,layout_anchor 指定参照物, anchorGravity 指定相对于参照物的位置,设置为 bottom|right则表示将FloatingActionButton放置于参照物的右下角。
注意点
- RecyclerView版本要是v22及以上,v21之前的版本不支持与CoordinatorLayout一起工作
- 和RecyclerView 22版本配合使用的时候会有一个已知的问题,如果滚动过快,会触发NullPointerException bug连接,不过这个问题应该已经修复了,我在recyclerview-v7:27版本中快速滑动已经没有这个问题了