CoordinatorLayout结合Behavior高级用法
来源:互联网 发布:杀破狼 js mp3 编辑:程序博客网 时间:2024/05/22 14:12
版权声明:本文来自Loader's Blog,未经博主允许不得转载。
目录(?)[-]
- 认识Behavior
- 初步自定义
- 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的时候,我们需要关心的两组四个方法,为什么分为两组呢?看一下下面两种情况
- 某个view监听另一个view的状态变化,例如大小、位置、显示状态等
- 某个view监听CoordinatorLayout里的滑动状态
对于第一种情况,我们关心的是: layoutDependsOn
和onDependentViewChanged
方法,
对于第二种情况,我们关心的是: onStartNestedScroll
和onNestedPreScroll
方法。
对于这几个方法什么意思,我们需要干什么,稍候我们就能了解到。
初步自定义
现在我们就来根据第一种情况尝试自定义一个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的时候就是拿的这个构造。我们覆写了两个方法layoutDependsOn
和onDependentViewChanged
,这两个方法的参数都是一样的,解释一下,第一个不用说,就是当前的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
和你想的一样,我们覆写了onStartNestedScroll
和onNestedPreScroll
方法,但是除了这两个方法外,我们还覆写了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
- CoordinatorLayout结合Behavior高级用法
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout behavior
- CoordinatorLayout.Behavior
- Tablayout,CoordinatorLayout与Behavior
- 深入理解CoordinatorLayout.Behavior
- CoordinatorLayout与Behavior
- CoordinatorLayout与Behavior总结
- 自定义实现CoordinatorLayout.Behavior
- AppBarLayout&CoordinatorLayout&Behavior
- CoordinatorLayout 与Behavior
- CoordinatorLayout+Behavior讲解
- CoordinatorLayout之Behavior使用
- 全面掌控MySQL加锁规则
- 算法作业7
- ReactNative制作Component控件并且复用(二)
- 设计模式笔记五:原型模式
- 什么时候需要清楚浮动?清除浮动的方法总结
- CoordinatorLayout结合Behavior高级用法
- 高精度加法
- java web.xml中可以配置些什么
- 值传递和地址传递的理解
- C面试题目
- DIY个人智能家庭网关——硬件篇之WIFI灯带DIY
- openresty 应用打包并使用luajit编译lua代码实现简单加密
- 算法作业7运行
- 集合案例练习