欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android自定义控件跟随手指移动及view事件分发机制

程序员文章站 2022-06-09 09:49:14
...

 我们都知道自定义控件流程onmeasure(),onlayout(),ondraw(),那么是不是所有得自定义都要重写这三个方法呐,肯定不是的,onmeasure()只是测量控件大小,onlayout(),测量大小后需要控件显示位置,最后通过ondraw()进行绘制.

言归正算自定义控件让控件跟随手指移动,很明显只需要监听手指移动,来改变控件位置,而不需要去重写其他方法:这里我举一个FloatingActionButton的例子:

  

//自定义悬浮按钮
class CustomFloatingActionButton(context: Context, attr: AttributeSet) : FloatingActionButton(context, attr) {
    var down_x = 0f
    var down_y = 0f
//    var move_x = 0f
//    var move_y = 0f
    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        when (ev!!.action) {
            MotionEvent.ACTION_DOWN -> {
                down_x = ev.rawX
                down_y = ev.rawY
//                move_x = ev.rawX
//                move_y = ev.rawY
            }
            MotionEvent.ACTION_MOVE -> {
                layout(
                    (ev.rawX - down_x + left).toInt(),
                    (ev.rawY - down_y + top).toInt(),
                    (ev.rawX - down_x + right).toInt(),
                    (ev.rawY - down_y + bottom).toInt()
                )

                down_x = ev.rawX
                down_y = ev.rawY
                invalidate()
            }
            MotionEvent.ACTION_UP -> {
//                if (abs(down_x - move_x) < 5f && abs(down_y - move_y) <= 5f) {
//                    performClick()
////                    isPressed = true
//                    return super.onTouchEvent(ev)
//                }
            }
        }

        return true//如果返回true,从手指接触屏幕到手指离开屏幕,将不会触发点击事件。
    }


}

通过代码我们可以看到,重写ontouchevent()方法,监听手势,通过滑动初始位置来设置控件位置,最后调用invalidate()重新绘制.

写在最后:可以看到我们的ontouchevent()最后返回的是true,根据注解返回true就不会执行onclick事件,这是为什么呐?额这就设计到view的事件分发了,在android中事件分发机制主要在activity,viewgroup,view中,今天我就讲下view的事件分发(子view)

在了解view事件分发时你必须知道三个函数,dispatchTouchevent(),onintercepTouchEvent(),ontouchevent(),然而我们今天讲的view事件分发就不存在onintercepTouchEvent()方法了,这个很好理解一个子view要么处理事件要么不处理事件,根本不存在事件拦截之说,dispatchTouchevent()事件分发,这个函数一般我们都不会重写他,并且都是默认返回super.dispatchTouchevent.内部交给ontouchevent处理.但是如果返回true就表明事件消耗了,不再向下分发,如果返回false就表明此view不消耗此次事件,返回上一级viewgroup处理.

注:如果dispatchTouchevent()返回super.dispatchTouchevent,由于view事件分发顺序是ontouch-ontouchevent-onclick

如果我们view中没用ontouch事件,那么默认返回的return super.ontouch..,默认值就是false,此时才会执行ontouchevent事件,如果设置了ontouch事件并且返回的true,那么就不会执行,ontouchevent更别说什么Onclick了。

那么ontouchevent中默认返回的super.ontouchevent也是false,但是我们可以看他源码是实现了onclick的,(通过源码可看到实现onclick是有一些列条件的).如果ontouchevent返回true就表明消耗此时事件,不向下分发也就是不走onclick方法了.当然我们可以在ontouchevent里面直接调用.performclick(),可以监听onclick事件,流程可能不是那么清晰.但是对于对事件分发有一定基础的应该不难理解