上次简单的说了一下CoordinatorLayout的基本用法(android特性之CoordinatorLayout用法探析实例)。其中CoordinatorLayout给我们提供了一种新的事件的处理方式,Behavior。还记得那一串字符串吗?
1 | app:layout_behavior= "@string/appbar_scrolling_view_behavior" |
其实它并不是一个字符串资源,而它代表的是一个类,就是一个Behavior,这玩意其实还可以自定义的。
首先,来让我见识一下它的真面目:
1 2 3 | public static abstract class Behavior<V extends View> { ... } |
Behavior是CoordinatorLayout的一个内部泛型抽象类。内部类中指定的view类型规定了哪种类型的view的可以使用才Behavior。因此,如果没有特殊需求,直接指定view为View就行了。
1.某个view需要根据监听另一个的行为来控制自己的行为,这个时候我们需要重写2个方法:
1 2 3 | public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) { return false ; } |
1 2 3 | public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) { return false ; } |
2.我们的view需要根据监听CoordinatorLayout中的子view的滚动行为来改变自己的状态,现在我们就需要重写下面的方法了:
1 2 3 4 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { return false ; } |
1 2 3 4 | public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int [] consumed) { // Do nothing } |
下面我们先来看一下情况1,让一个view跟随另一个view的行为而实现状态的改变。我们定义一个Behavior,名字叫:FooterBehavior,代码如下:
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 | package com.lingyun.coordinatorlayoutdemo; import android.content.Context; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.util.AttributeSet; import android.view.View; /** * Created by dandy on 2016/7/4. */ public class FooterBehavior extends CoordinatorLayout.Behavior<View>{ public FooterBehavior(Context context,AttributeSet attributeSet){ super (context,attributeSet); } @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof AppBarLayout; } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { float scaleY = Math.abs(dependency.getY()) / dependency.getHeight(); child.setTranslationY(child.getHeight() * scaleY); return true ; } } |
我们在自定义的Behavior中,带有参数的这个构造必须要重载,因为在CoordinatorLayout里利用反射去获取这个Behavior的时候就是拿的这个构造。
在layoutDependsOn中,我们设置让View的状态来跟随AppBarLayout,也就是说只有AppBarLayout的状态发生变化才会影响到View。
接下来就是在onDependentViewChanged中对View做出相应的状态改变。在代码中,我们做的改变是,跟随dependedcy一起在Y轴方向移动,来达到显示和隐藏的目的。先布局如下:
activity_main.xml布局:
1 2 3 4 5 6 7 8 9 | <? xml version = "1.0" encoding = "utf-8" ?> < android.support.design.widget.CoordinatorLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "match_parent" android:layout_height = "match_parent" > < include layout = "@layout/appbar_main" /> < include layout = "@layout/content_main" /> < include layout = "@layout/footer_main" /> </ android.support.design.widget.CoordinatorLayout > |
appbar_main.xml布局如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <? xml version = "1.0" encoding = "utf-8" ?> < android.support.design.widget.AppBarLayout 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 = "wrap_content" android:theme = "@style/ThemeOverlay.AppCompat.Dark.ActionBar" > < android.support.v7.widget.Toolbar android:id = "@+id/toolbar" android:layout_width = "match_parent" android:layout_height = "?attr/actionBarSize" app:popupTheme = "@style/ThemeOverlay.AppCompat.Light" android:background = "?attr/colorPrimary" app:layout_scrollFlags = "scroll|enterAlways" /> </ android.support.design.widget.AppBarLayout > |
content_main.xml布局如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <? xml version = "1.0" encoding = "utf-8" ?> < android.support.v4.widget.NestedScrollView 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" app:layout_behavior = "@string/appbar_scrolling_view_behavior" > < TextView android:layout_width = "match_parent" android:layout_height = "match_parent" android:gravity = "center" android:text = "你是谁?你从哪里来?你到哪里去?" /> </ android.support.v4.widget.NestedScrollView > |
footer_main.xml布局如下:
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 | <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:app = "http://schemas.android.com/apk/res-auto" android:orientation = "horizontal" android:layout_width = "match_parent" android:layout_height = "60dp" android:layout_gravity = "bottom" android:background = "?attr/colorPrimary" app:layout_behavior = "com.lingyun.coordinatorlayoutdemo.FooterBehavior" > < TextView android:layout_width = "0dp" android:layout_height = "match_parent" android:text = "Tab1" android:layout_weight = "1" android:gravity = "center" android:textColor = "@android:color/white" /> < TextView android:layout_width = "0dp" android:layout_height = "match_parent" android:text = "Tab2" android:layout_weight = "1" android:gravity = "center" android:textColor = "@android:color/white" /> < TextView android:layout_width = "0dp" android:layout_height = "match_parent" android:text = "Tab3" android:layout_weight = "1" android:gravity = "center" android:textColor = "@android:color/white" /> </ LinearLayout > |
注意看,在footer_main.xml中我们设置了
1 | app:layout_behavior= "com.lingyun.coordinatorlayoutdemo.FooterBehavior" |
这正好就是我们自定义的FooterBehavior的绝对路径。下面我们来看一下效果图:
在效果图上我们看到,当我们上下滑动屏幕的时候,底部footer布局和标题Toolbar一起移动,实现了显示和隐藏的效果。
学会了第一张简单的自定义Behavior之后,接下来我们再来看一下第二种情况,滑动。因为这个是根据CoordinatorLayout里子view的滚动行为来改变我们的状态的,所以情况1中的2个方法我们就不需要重写了。下面,我们用情况2来实现上面的效果。
先来看一下下面几个参数:
child:简单点说,就是用到当前CoordinatorLayout的子View,响应此Behavior。
target:CoordinatorLayout的子View,引起滚动的view,其实child的状态改变是根据target来实现的。
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 | package com.lingyun.coordinatorlayoutdemo; import android.content.Context; import android.support.design.widget.CoordinatorLayout; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; /** * Created by dandy on 2016/7/4. */ public class FooterBehavior extends CoordinatorLayout.Behavior<View>{ private float targetY = - 1 ; private static final String TAG = "FooterBehavior" ; public FooterBehavior(Context context,AttributeSet attributeSet){ super (context, attributeSet); } @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { if (targetY == - 1 ){ targetY = target.getY(); } return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0 ; } @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int [] consumed) { super .onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); float scrooY = targetY - Math.abs(target.getY()); float scaleY = scrooY / targetY; child.setTranslationY(child.getHeight() * scaleY); } } |
在方法onStartNestedScroll中,首先获取target在Y轴上距离屏幕顶端的距离,然后判断是否是在Y轴上滚动。
方法onNestPreScroll中,就是时时根据target距离屏幕顶端的距离计算出滚动的距离,然后根据比例计算出child移动的距离。
截图和上面比较没啥区别:
基本的自定义Behavior就是这样了,以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
转自 https://www.jb51.net/article/134141.htm