CoordinatorLayout结合Behavior高级用法

来源:互联网 发布:杀破狼 js mp3 编辑:程序博客网 时间:2024/05/22 14:12

目录(?)[-]

  1. 认识Behavior
  2. 初步自定义
  3. Scroll Behavior

在新的support design中,CoordinatorLayout可以说是最重要的一个控件了,CoordinatorLayout给我们带来了一种新的事件的处理方式——behavior,你是不是还记得我们在使用CoordinatorLayout的时候,一些子view需要一段,

app:layout_behavior="@string/appbar_scrolling_view_behavior"
  • 1
  • 1

这样的xml配置?当时我们不知道这是干嘛的,直接照用就行了,后来发现这玩意是一个类!而且我们还可以自定义!所以,今天这篇博客我们首先来学习一下如何自定义Behavior,之后的博客可能会看一下CoordinatorLayout是怎么处理这个Behavior的。

认识Behavior

Behavior是CoordinatorLayout的一个抽象内部类

public abstract static class Behavior<V extends View> {      public Behavior() {      }      public Behavior(Context context, AttributeSet attrs) {      }      ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

有一个泛型是指定的我们应用这个Behavior的View的类型,例如上面的appbar_scrolling_view_behavior对应的字符串其实是Android.support.design.widget.AppBarLayout$ScrollingViewBehavior,这个ScrollingViewBehavior内部类指定的泛型是View,所以理论上这个Behavior我们任何的View都可以使用,我们在自定义的时候,如果不是特殊的行为,也可以直接指定泛型View

在自定义Behavior的时候,我们需要关心的两组四个方法,为什么分为两组呢?看一下下面两种情况

  1. 某个view监听另一个view的状态变化,例如大小、位置、显示状态等
  2. 某个view监听CoordinatorLayout里的滑动状态

对于第一种情况,我们关心的是:
layoutDependsOnonDependentViewChanged方法,
对于第二种情况,我们关心的是:
onStartNestedScrollonNestedPreScroll方法。
对于这几个方法什么意思,我们需要干什么,稍候我们就能了解到。

初步自定义

现在我们就来根据第一种情况尝试自定义一个Behavior,这里我们实现一个简单的效果,让一个View根据另一个View上下移动。
首先我们来自定义一个Behavior,起名为DependentBehavior

public class DependentBehavior extends CoordinatorLayout.Behavior<View> {    public DependentBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {        return super.layoutDependsOn(parent, child, dependency);    }    @Override    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {        ViewCompat.offsetLeftAndRight();        return super.onDependentViewChanged(parent, child, dependency);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意一下,带有参数的这个构造必须要重载,因为在CoordinatorLayout里利用反射去获取这个Behavior的时候就是拿的这个构造。我们覆写了两个方法layoutDependsOnonDependentViewChanged,这两个方法的参数都是一样的,解释一下,第一个不用说,就是当前的CoordinatorLayout,第二个参数是我们设置这个Behavior的View,第三个是我们关心的那个View。如何知道关心的哪个呢?layoutDependsOn的返回值决定了一切!

这里我们关心一个TextView好了,所以layoutDependsOn可以这么写,

@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {    return dependency instanceof TextView;}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

现在设置好了关心谁,接下来就是在这个View状态发生变化的时候,我们现在的View该做些什么了,恩,这里肯定是在onDependentViewChanged做工作了。我们的任务就是获取dependency距离底部的距离,并且设置给child,很简单。

@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {    int offset = dependency.getTop() - child.getTop();    ViewCompat.offsetTopAndBottom(child, offset);    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

首先我们先获取两个View的top值的差,然后让child的位置位移一下就ok啦,如此简单,那这个简单的Behavior如何用呢?

<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:fitsSystemWindows="true"    tools:context="org.loader.mybehavior.MainActivity">    <TextView        android:id="@+id/depentent"        android:layout_width="100dp"        android:layout_height="100dp"        android:background="#FFFF0000"        android:gravity="center"        android:textColor="@android:color/white"        android:layout_gravity="top|left"        android:text="depentent"/>    <TextView        android:layout_width="100dp"        android:layout_height="100dp"        android:background="#FF00FF00"        android:gravity="center"        android:textColor="@android:color/white"        android:layout_gravity="top|right"        app:layout_behavior="org.loader.mybehavior.DependentBehavior"        android:text="auto"/></android.support.design.widget.CoordinatorLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

注意,第二个TextView我们设置了app:layout_behavior="org.loader.mybehavior.DependentBehavior"
值正好是我们定义的那个DependentBehavior

final TextView depentent = (TextView) findViewById(R.id.depentent);depentent.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        ViewCompat.offsetTopAndBottom(v, 5);    }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在Activity中,我们每次点击第一个TextView都会去改变一下它的位置,下面让我们来看看另一个TextView的位置改变了没有。

Scroll Behavior

在学会了如何自定义Behavior后,我们接着来实现上面说的第二种情况-滑动。为了演示这种Behavior的定义,我们还是来做个无用功,让一个ScrollView跟随另一个ScrollView滑动。恩,先来看看效果吧,

从效果中我们可以看出,第二个ScrollView明显是是在跟随第一个进行滑动,现在就让我们用自定义Behavior的形式实现它。
创建一个Behavior,起名叫ScrollBehavior,

public class ScrollBehavior extends CoordinatorLayout.Behavior<View> {    public ScrollBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    @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 onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);    }    @Override    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

和你想的一样,我们覆写了onStartNestedScrollonNestedPreScroll方法,但是除了这两个方法外,我们还覆写了onNestedPreFling方法,这个方法是干嘛的? 估计大家已经猜出来了,这里是处理fling动作的,你想想,我们在滑动松开手的时候,ScrollView是不是还继续滑动一会,那我们也需要让跟随的那个ScrollView也要继续滑动一会,这种效果,onNestedPreFling就派上用场了。

好,接下来我们来实现代码,首先来看看onStartNestedScroll,这里的返回值表明这次滑动我们要不要关心,我们要关心什么样的滑动?当然是y轴方向上的。

@Overridepublic boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {    return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

现在我们准备好了关心的滑动事件了,那如何让它滑动起来呢?还是要看onNestedPreScroll的实现

@Overridepublic void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {    super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);    int leftScrolled = target.getScrollY();    child.setScrollY(leftScrolled);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

也很简单,让child的scrollY的值等于目标的scrollY的值就ok啦,那fling呢?更简单,

@Overridepublic boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {    ((NestedScrollView) child).fling((int)velocityY);    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

直接将现在的y轴上的速度传递传递给child,让他fling起来就ok了。
定义好了Behavior,就得在xml中使用了,使用方法和前面的一样。

<?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"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true"    android:orientation="vertical">    <android.support.v4.widget.NestedScrollView        android:layout_gravity="left"        android:layout_width="wrap_content"        android:background="#FF00FF00"        android:layout_height="match_parent">        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:orientation="vertical">            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentLeft"/>        </LinearLayout>    </android.support.v4.widget.NestedScrollView>    <android.support.v4.widget.NestedScrollView        android:layout_gravity="right"        android:layout_width="wrap_content"        android:background="#FFFF0000"        android:layout_height="match_parent"        app:layout_behavior="org.loader.mybehavior.ScrollBehavior">        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:orientation="vertical">            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:paddingTop="50dp"                android:paddingBottom="50dp"                android:textColor="@android:color/white"                android:text="contentRight"/>        </LinearLayout>    </android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131

第二个ScrollView的layout_behavior我们指定为org.loader.mybehavior.ScrollBehavior,现在就可以看到上面的效果了。

ok, 最后是文章中demo的代码下载:http://download.csdn.net/detail/qibin0506/9352989

0 0