上一篇我们讲了自定义behavior监听控件的状态变化:例如垂直方向位移的变化。今天我们要谈的是如何监听控件的滑动事件。就是说当布局文件里有一个可滑动的控件(如RecyclerView、NestedScrollView、Viewpager页面里的NestedScrollView)滑动时,我们自定义的behavior可以帮观察者监听到该类事件,同时做相应的处理。我们还是从布局文件讲起,在此之前先看以下运行效果:
1. 布局文件
<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.v4.widget.NestedScrollView
android:id="@+id/nestedScroll"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="left">
<LinearLayout
android:id="@+id/nestedScrollLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/bt2"
android:layout_margin="50dp"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d1"
android:textColor="@color/white" />
<ImageView
android:layout_margin="50dp"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d2"
android:textColor="@color/white" />
<ImageView
android:layout_margin="50dp"
android:id="@+id/bt1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d2"
android:textColor="@color/white" />
<ImageView
android:layout_margin="50dp"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d2"
android:textColor="@color/white" />
<ImageView
android:layout_margin="50dp"
android:id="@+id/bt21"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d2"
android:tag="tv1"
android:textColor="@color/white" />
<ImageView
android:layout_margin="50dp"
android:id="@+id/bt23"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left|top"
android:background="@drawable/d2"
android:tag="tv1"
android:textColor="@color/white" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<ImageView
android:background="@drawable/d1"
android:id="@+id/obeserver"
android:layout_marginRight="20dp"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_gravity="right|center_vertical"
android:text="观察者"
app:layout_behavior="com.example.custombehavior.ListenerScrollBehavior" />
</android.support.design.widget.CoordinatorLayout>
在这里我们声明一个被观测者NestedScrollView,再声明一个观察者NestedScrollView,同时为观察者配置一个自定义behavior:layout_behavior="com.example.custombehavior.ListenerScrollBehavior". 我们看到这个布局的根布局仍然是CoordinatorLayout,这与我们之前的一样,CoordinatorLayout布局捕捉到事件及控件状态变化后,分发给我们自定义的behavior。接下来我们就来看一下这个自定义behavior的实现,看它是如何来监听控件的滑动事件。
2. 自定义Behavior实现
package com.example.custombehavior;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.Random;
public class ListenerScrollBehavior extends Behavior<View> {
public ListenerScrollBehavior(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
// TODO Auto-generated constructor stub
}
/**
* 用来决定谁是观察者,谁是被观察者
* @param coordinatorLayout ,父容器
* @param child, 观察者
@param directTargetChild,被观察者
@param target: 与directTargetChild指的是同一个控件NestedScrollView
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
View child, View directTargetChild, View target,
int nestedScrollAxes) {
// TODO Auto-generated method stub
//监听垂直滚动
return (nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL)||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
target, nestedScrollAxes);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout,
View child, View target, int dx, int dy, int[] consumed) {
// TODO Auto-generated method stub
child.animate().rotation( dy* 360);
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout,
View child, View target, float velocityX, float velocityY,
boolean consumed) {
return super.onNestedFling(coordinatorLayout, child, target, velocityX,
velocityY, consumed);
}
}
这里和上一篇类似,只是重写的函数不一样,我们来介绍以下几个函数“
1.onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes);
CoordinatorLayout :根布局
child:观察者
directTargetChild:被观察者
target:还是被观察者,在这里与directTargetChild指向的控件是同一个
nestedScrollAxes:将要监听的滚动方向,垂直还是水平。
child是观察者,对应布局里的id为observer控件 ;directTargetChild是被观察者,对应布局里的id为NestedScrollView控件。
nestedScrollAxes表示滚动的方向。在此我们return (nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL)表示我们只监听NestedScrollView的垂直滑动事件。
2.onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed)
当滑动时执行。
CoordinatorLayout :根布局
child:观察者
target:被观察者,在这里与directTargetChild指向的控件是同一个
nestedScrollAxes:将要监听的滚动方向,垂直还是水平。
dx:每次滚动的水平距离
dy:每次滚动的垂直距离
这里我们让观察者child执行动画:child.animate().rotation( dy* 360); 这样就实现了观察者监听到滑动事件并作出相应的处理。
3. onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed)
滚动的惯性。在这里我们没有用到,用于监听滚动的惯性,就是当人手指松开后列表还会滑动一段距离,我们可以检测到velocityX与velocityY两个惯性值,运用场景可以是:当滑动一个列表时,让另一个列表 跟着滑动,而且另一个列表的惯性值要与列表1的惯性值一样,才能真正保持同步滑动。
CoordinatorLayout :根布局
child:观察者
target:被观察者
velocityX 轴滚动的惯性值,就是人手指松开后列表还会滑动一段距离
velocityY 轴滚动的惯性值,就是人手指松开后列表还会滑动一段距离
consumed: 这个还不理解,望请指教。