自Google推出CoordinatorLayout,其中最经典的设计Behavior就被广大开发者频频称道,其主要功能就是使布局中的指定控件(使用behavior属性)可以跟随其它组件进行协同操作,例如滑动隐藏Toolbar、动态改变FloatingActionButton的高度等。用好Behavior,可使界面控件的动作配合更加协调
Android本身自带了一个Behavior的实现,如下:
- appbar_scrolling_view_behavior
该Behavior可以实现Appbar在视图滑动时进行隐藏等效果,如果你的需求符合该定义,则直接通过
- app:layout_behavior=”appbar_scrolling_view_behavior”
使用即可(注意命名空间引入)。
言归正传,下面说一下自定义Behavior该如何实现
自定义Behavior有两种方式:
通过定义的View监听CoordinatorLayout里的滑动状态
对于该方法,我们主要关注onStartNestedScroll和onNestedPreScroll方法通过定义的View监听另一个View的状态变化
对于该方法,我们需要注意layoutDependsOn和onDependViewChanged方法
当然,上述方法的基础是,要自定义一个类并继承CoordinatorLayout.Behavior,并重写相应的方法进行事件监听,然后将该Behavior的全路径,通过app:layout_behavior方法设置给相应控件
此处以我的毕业设计中商品详情页为例:
此处实现了底部价格和购买按钮的跟随滑动,上部Toolbar的滑动由内置的Behavior完成,具体实现代码如下:
Tips:我使用了第一种方法进行实现,因为其可定制性较高。第二种方法是注释的代码,效果和第一种略有不同,看需求。
class FooterBehavior(private val context: Context, private val attributeSet: AttributeSet) : CoordinatorLayout.Behavior<View>(context, attributeSet) {
// override fun layoutDependsOn(parent: CoordinatorLayout?, child: View?, dependency: View?): Boolean {
// return dependency is AppBarLayout
// }
//
// override fun onDependentViewChanged(parent: CoordinatorLayout?, child: View?, dependency: View?): Boolean {
// val translationY = Math.abs(dependency!!.y)
// child?.translationY = translationY
log(LogType.DEBUG, "behavior", dependency!!.y.toString())
// return true
// }
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout?, child: View?, directTargetChild: View?, target: View?, nestedScrollAxes: Int): Boolean {
return (nestedScrollAxes shl ViewCompat.SCROLL_AXIS_VERTICAL) != 0
}
private var transY = 0f
override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout?, child: View?, target: View?, dx: Int, dy: Int, consumed: IntArray?) {
val h: Float = (child!!.height + 100).toFloat()
if (dy > 0 && transY <= h) {
transY += dy
if (transY > h) transY
child!!.translationY = transY
} else if (dy < 0) {
transY += dy
if (transY < 0) transY = 0f
child!!.translationY = transY
}
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed)
}
}
第一种方法的实现思路(仅是Kotlin代码,Java通用)
- onStartNestedScroll:该方法用来确定关心的滑动方向,主要关注最后一个参数,其回调传入的值为具体的滑动方向,可以通过相应运算确定是否捕获。其余参数的意义通过参数名即可清楚
- onNestedPreScroll:该方法内传入的参数为被监听的View以及需要操作的View,和相应的滑动参数。在方法内通过对滑动参数的运算,动态操作child,即可实现控件协同操作
第二种方法的实现思路(仅是Kotlin代码,Java通用)
- layoutDependsOn:该方法确定关注哪个控件的滑动事件,主要注意dependency参数,其代表滑动的控件,返回值为真则监听该控件事件
- onDependentViewChanged:在方法内,通过对被监听对象的位置运算,实现控件的同步操作。该方法与第一种方法相比,参数更为简单,实现起来方便,但限制也是明显的,所以适合页面需求较为单一的滑动监听。例如同步收放等。
使用Behavior最重要的一点就是,控件的跟布局一定是CoordinatorLayout,而且一定要指定好控件,否则是没有效果的。
本章参考了《Android进阶之光》一书,其中原理多数来自该书第二章2.2.6节,此处通过自我实践与书中理论相结合,分享给大家,希望对你有帮助。
写于:2017年9月17日 18:26