前言
用过CoordinatorLayout的小伙伴应该都会发现,在这个布局里面,我们有一个behavior属性,可以实现一些比较不错的动画效果,比如折叠式toolbar,snackbar顶起floatingActionBar等等,那么今天我们就来自定义一个behavior实现我们想要的效果。
最终效果演示
左边的View是可以随着手指拖动的,右边的button的x轴反向移动,y轴相同
跟随手指移动的view
这个实现起来比较简单,重写触摸事件即可,直接贴代码了
class MoveView : TextView {
constructor(context: Context?) : this(context, null)
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var downX : Float = 0.0f
private var downY : Float = 0.0f
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
downX = event.x
downY = event.y
}
MotionEvent.ACTION_MOVE -> {
//x是滑动的距离
translationX = x + (event.x - downX)
translationY = y + (event.y - downY)
}
MotionEvent.ACTION_UP -> {
downX = event.x
downY = event.y
}
}
return true
}
}
传统实现跟随滑动方式
1.在MoveView中添加button,加入相关的逻辑操作
2.在Activity中通过GestureDetector改变button的位置
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val gestureDetector = GestureDetector(this,object : GestureDetector.OnGestureListener {
override fun onShowPress(e: MotionEvent?) {}
override fun onSingleTapUp(e: MotionEvent?): Boolean { return false }
override fun onDown(e: MotionEvent?): Boolean { return false }
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean { return false }
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
//在屏幕上拖动事件
btn.x = windowManager.defaultDisplay.width - mv.x
btn.y = mv.y
return false
}
override fun onLongPress(e: MotionEvent?) {}
})
mv.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
}
}
上面2种方式确实可以实现上述效果,但是,可扩展性基本为0,如果我现在想把button改成imageview,如果是第一种方式,我就不得不去修改MoveView中的代码,如果是第二种方式,我就必须去修改Activity中的代码,这显然不行,如果多个地方都用到这种效果,代码量就很大了,而且不灵活。
自定义behavior实现
我们只需要继承CoordinatorLayout.Behavior,然后重写layoutDependsOn和onDependentViewChanged这两个方法即可,剩下的操作全部在这里执行,然后给你想要实现拖动的view添加一个behavior即可。
class CustomBehavior : CoordinatorLayout.Behavior<View> {
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
/**
* 判断child是否依赖dependency,也可以理解为是否要响应behavior,如果用户操作的view是你需要的view,那么就响应
*/
override fun layoutDependsOn(parent: CoordinatorLayout?, child: View?, dependency: View?): Boolean {
Log.d("lxt", (dependency is MoveView).toString())
//返回true,响应事件
return dependency is MoveView
}
/**
* 当dependency发生改变时(位置、宽高等),执行这个函数
* 返回true表示child的位置或者是宽高要发生改变,否则就返回false
*/
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
//根据dependency的位置,设置child的位置
Log.d("lxt", dependency.y.toString())
val left = dependency.x
val screenWidth = parent.width
child.x = screenWidth - left - child.width
child.y = dependency.y
return true
}
}
用behavior的好处显而易见
网友评论