Android自带的Behavior是AppBarLayout.ScrollingViewBehavior
,对应的xml中的app:layout_behavior="@string/appbar_scrolling_view_behavior"
属性。
我们可以自定义Behavior
实现各个view和组件的交互和滑动。
有俩种方法
- 1.定义的view来监听CoordinateLayout中的滑动状态。
- 2.定义的view1来监听另外一个view2的状态变化,比如view2的大小,高度,位置变化,滑动状态等等。
具体处理
第1种
重写onStartNestedScroll()
和onNestedPreScroll()
方法
第2种
重写layoutDependsOn()
和onDependentViewChanged()
方法。
效果示例
虽然看起来效果差不多,但是俩个图的实现原理是不一样的。
方法1:view来监听CoordinateLayout中的滑动状态实现方法
1.布局文件
<?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"
tools:context="com.minminaya.behaviordemotest.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:title="Toolbar" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/reclcerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
//这里加入自定义Behavior的包名,而且要在CoordinatorLayout 的子节点下
app:layout_behavior="com.minminaya.behaviordemotest.behavior.BehaviorForCoordinatorScroll"
android:layout_gravity="bottom">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义Behavior的view"
android:textColor="#000"
android:textSize="21sp" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
2.新建一个类BehaviorForCoordinatorScroll
继承自CoordinatorLayout.Behavior<View>
,重写onStartNestedScroll()
和onNestedPreScroll()
方法:
-
onStartNestedScroll()
:它的返回值代表本次滑动要不要关心 -
onNestedPreScroll()
:用于处理具体滑动逻辑,它的dx,dy参数分别代表了水平滑动和垂直滑动的距离,比如dy上滑为正,根据其来确定view滑动的具体逻辑
import android.content.Context;
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.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
/**
* 自定义监听
* Created by Niwa on 2017/8/16.
*/
public class BehaviorForCoordinatorScroll extends CoordinatorLayout.Behavior<View> {
/**
* 滑动距离累加值
*/
private int directionChange = 0;
public BehaviorForCoordinatorScroll(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
//返回值表明这次滑动我们要不要关心,这里关心的是Y轴方向上的
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if (dy > 0 && directionChange < 0 || dy < 0 && directionChange > 0) {
child.animate().cancel();
Log.e("CustomBehavior1", "reset");
//dy是一直刷新的,累加值会一直加到很大或者很小,这里累加值归零0的触发条件是
// 1.向上滑,并且累加值是负的(说明上次滑动是向下)
//2.向下滑,并且累加值是正的(说明上次滑动是向上)
directionChange = 0;
}
directionChange += dy;
Log.e("CustomBehavior1", "dy:" + dy);
Log.e("CustomBehavior1", "directionChange:" + directionChange);
if (directionChange > child.getHeight()) {
Log.e("CustomBehavior1", "上滑");
hide(child);
}
if (directionChange < 0) {
Log.e("CustomBehavior1", "下滑");
show(child);
}
}
private void show(final View child) {
final ViewPropertyAnimator animator = child.animate()
.translationY(0)
.setInterpolator(new FastOutSlowInInterpolator())
.setDuration(200);
animator.start();
}
private void hide(final View child) {
final ViewPropertyAnimator animator = child.animate()
.translationY(child.getHeight())
.setInterpolator(new FastOutSlowInInterpolator())
.setDuration(200);
animator.start();
}
}
方法2:view1来监听另外一个view2的状态变化实现方法
1.新建一个类BehaviorForViewStateScroll
继承自CoordinatorLayout.Behavior<View>
,把布局文件中的属性改为这个类app:layout_behavior="com.minminaya.behaviordemotest.behavior.BehaviorForViewStateScroll"
重写layoutDependsOn()
和onDependentViewChanged()
方法:
layoutDependsOn()
:用来返回我们需要关心的类
onDependentViewChanged()
:根据我们关心的View的变化处理具体目的view处理逻辑
import android.content.Context;
import android.support.design.widget.AppBarLayout;
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.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
/**
* 自定义监听
* Created by Niwa on 2017/8/16.
*/
public class BehaviorForViewStateScroll extends CoordinatorLayout.Behavior<View> {
public BehaviorForViewStateScroll(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//具体逻辑,获取当前的AppBarLayout的可见部分的y轴坐标大小
float transitionY = Math.abs(dependency.getY());
//目的view设置变化
child.setTranslationY(transitionY);
//表明已处理事件
return true;
}
}
注意事项
- 一定不要漏了自定义Behavior中的构造函数!!!!!!
- 注意动画的使用如果不及时停止可能会导致内存泄露从而闪退
end