上次讲了自定义Behavior的child监听dependency的状态变化,这次就接着说child监听实现了NestedScrollingChild的接口的dependency的滑动状态。
需要重写两个方法
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
先来看onStartNestedScroll,这个方法表明我们在这次滑动中关心的方向,如果是X轴,则return nestedScrollAxes == ViewCompat.SCROLL_AXIS_HORIZONTAL;若是关心Y轴方向的滑动,return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL即可。
onNestedScroll这个方法才是我们关注的重点,coordinatorLayout这个参数就不说了,child是指设置了这个Behavior的coordinatorLayout的子View,target则是前面提到的实现了NestedScrollingChild的接口的dependency。dxConsumed、dyConsumed是指x、y轴方向上target消费的像素值,简单来说,就是滚动的距离,至于后面两个参数,百度了,也看了源码的注释,还是不太明白,翻译过来字面意思就是:不被目标自身的滚动操作所消耗的垂直、水平像素,而是用户要求的(本来以为是调用scrollto之类方法产生的,试过了发现不是)。
说完这么多屁话,看个例子
先上效果图
仔细看还是和之前的有点区别,在上滑和下滑时,隐藏显示FloatingActionButton和BottomBar。
XML
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="0dp">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="topBar"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:behavior_overlapTop="30dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<include layout="@layout/layout_main" />
</android.support.v4.widget.NestedScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="bottomBar"
app:layout_behavior=".BottomScrollBehavior" />
<android.support.design.widget.FloatingActionButton
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="70dp"
android:layout_marginRight="20dp"
android:src="@mipmap/ic_launcher_round"
app:elevation="5dp"
app:layout_behavior=".ScrollingBehavior" />
</android.support.design.widget.CoordinatorLayout>
也和上一篇的相似,唯一的区别就是BottomBar和FloatingActionButton的Behavior换了
再看自定义的Behavior
ScrollingBehavior
public class ScrollingBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
//是否正在执行动画的标示符
private boolean isAnimator;
public ScrollingBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimator && child.getVisibility() == View.VISIBLE) {
hideAnimator(child);
} else if ((dyConsumed < 0 || dyUnconsumed < 0) && !isAnimator && child.getVisibility() != View.VISIBLE) {
showAnimator(child);
}
}
private void showAnimator(View view) {
view.setVisibility(View.VISIBLE);
ViewCompat.animate(view)
.scaleX(1.0f)
.scaleY(1.0f)
.alpha(1.0f)
.setDuration(800)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
isAnimator = true;
}
@Override
public void onAnimationEnd(View view) {
isAnimator = false;
}
@Override
public void onAnimationCancel(View view) {
isAnimator = false;
}
})
.start();
}
private void hideAnimator(View view) {
ViewCompat.animate(view)
.scaleX(0)
.scaleY(0)
.alpha(0)
.setDuration(800)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
isAnimator = true;
}
@Override
public void onAnimationEnd(View view) {
isAnimator = false;
view.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(View view) {
isAnimator = false;
}
})
.start();
}
}
BottomScrollBehavior
public class BottomScrollBehavior extends CoordinatorLayout.Behavior<View> {
private boolean isAnimator;
public BottomScrollBehavior(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 onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimator && child.getTranslationY() == 0) {
hideAnimator(child);
} else if ((dyConsumed < 0 || dyUnconsumed < 0) && !isAnimator && child.getTranslationY() == child.getHeight()) {
showAnimator(child);
}
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
private void showAnimator(View view) {
ViewCompat.animate(view)
.translationY(0)
.setDuration(800)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
isAnimator = true;
}
@Override
public void onAnimationEnd(View view) {
isAnimator = false;
}
@Override
public void onAnimationCancel(View view) {
isAnimator = false;
}
})
.start();
}
private void hideAnimator(View view) {
ViewCompat.animate(view)
.translationY(view.getHeight())
.setDuration(800)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
isAnimator = true;
}
@Override
public void onAnimationEnd(View view) {
isAnimator = false;
}
@Override
public void onAnimationCancel(View view) {
isAnimator = false;
}
})
.start();
}
}