自定义behavior

前言

用过CoordinatorLayout的小伙伴应该都会发现,在这个布局里面,我们有一个behavior属性,可以实现一些比较不错的动画效果,比如折叠式toolbar,snackbar顶起floatingActionBar等等,那么今天我们就来自定义一个behavior实现我们想要的效果。

最终效果演示

左边的View是可以随着手指拖动的,右边的button的x轴反向移动,y轴相同


自定义behavior_第1张图片

跟随手指移动的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 {

    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的好处显而易见

1.不用修改MoveView中的任何代码
2.不用在Activity中添加任何代码
3.可以给任何你想要实现效果的view添加behavior,耦合度为0
自定义behavior_第2张图片

你可能感兴趣的:(自定义behavior)