前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android中单个View的触摸事件分发机制

Android中单个View的触摸事件分发机制

作者头像
fanfan
发布2022-05-07 14:58:47
7580
发布2022-05-07 14:58:47
举报
文章被收录于专栏:编程思想之路编程思想之路

有时会遇见这个问题:假设一个textview文本显示一个网址,程序中既给它注册长按事件操作,然后又会单击打开网页,也就是说既有onLongClick事件又有onClick事件。如果你只是点击一下,不会出问题,但如果你长按会发现在执行长按事件后也会执行单击事件,这是什么原因呢?接下来就进行分析对于view的触摸事件的执行,分析几两个问题,

为什么onClick时不会产生点击和长按的冲突?

为什么onLongClick时会执行完长按操作,再紧接着直接点击操作?

屏幕的滑动事件?

对于view的触摸事件有三个动作:

ACTION_DOWN:按下

ACTION_MOVE:移动

ACTION_UP:弹起

对于一个view,有touch事件,drag事件,click事件,所涉及到的listener方法如下

以TextView为例,给textview添加listener:

setOnTouchListener:覆写父接口OnTouchListener的onTouch方法,当触摸view时会触发该listener

setOnClickListener:覆写父接口OnClickListener的onClick方法,当点击view时会触发该listener

setOnLongClickListener:覆写父接口OnLongClickListener的onLongClick方法,当长按view时会触发该listener

代码语言:javascript
复制
public class MainActivity extends Activity implements View.OnClickListener,View.OnTouchListener,
        View.OnDragListener,View.OnLongClickListener{


    private String TAG = "MainActivity";
    private TextView mTestView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTestView = (TextView) findViewById(R.id.test_tv);
        mTestView.setOnTouchListener(this);
        mTestView.setOnClickListener(this);
        mTestView.setOnDragListener(this);
        mTestView.setOnLongClickListener(this);
    }



    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG,"---onTouchEvent---");
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG,"---dispatchTouch--");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.test_tv:
                Log.i(TAG,"----onClick----");
                break;
            default:
                break;
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.i(TAG,"----onTouch---");
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG,"---onTouch--ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG,"---onTouch--ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG,"---onTouch--ACTION_UP");
                break;
        }
        return false;
    }

    @Override
    public boolean onDrag(View v, DragEvent event) {
        Log.i(TAG,"---onDrag---");
        return false;
    }

    @Override
    public boolean onLongClick(View v) {
        Log.i(TAG,"---onLongClick---");
        return false;
    }
}

还有dispatchTouchEvent:注意,这是覆写父类Activity的方法,为该activity中的控件的触摸事件进行分发,分发的意思也就是说,如果该方法返回true,当你对activity中的view进行点击,长按,滑动等操作时Log信息如下:

代码语言:javascript
复制
<span style="font-size:14px;">05-18 00:57:45.450 6229-6229/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:57:45.470 6229-6229/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:57:45.500 6229-6229/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:57:47.340 6229-6229/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:57:48.120 6229-6229/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--</span>

也就是说返回true的话,点击,长按,滑动事件不会被分发到view的listener中,不会去执行任何操作,也就是触摸事件到这里就截止了,不会再往下传。

如果返回false,则事件就会被分发到view。默认的是返回的false

在此声明:当屏幕进行触摸时首先是activity感受到该触摸事件,然后对事件进行分发处理,也就是说要不要传给activity中的view进行处理。在事件进行分发时,首先判断点击的位置是否处于view的范围,如果不属于会执行onTouchEvent方法,如果属于然后再分发到view。activity首先将事件分发到你所定义的最外层的view,在本程序中我只定义了一个view,所以当dispatchTouchEvent返回false进行事件分发时就理所当然的分发给了我所定义的view

当对view进行点击时Log如下:(此时dispatchTouch定义其返回false)

代码语言:javascript
复制
05-18 21:01:41.290 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 21:01:41.290 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 21:01:41.290 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_DOWN
05-18 21:01:41.320 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 21:01:41.320 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 21:01:41.330 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_MOVE
05-18 21:01:41.790 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---onLongClick---
05-18 21:01:42.220 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 21:01:42.230 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 21:01:42.230 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_UP
05-18 21:01:42.230 24695-24695/com.fang.zrf.qrcodedemo I/MainActivity: ----onClick----

长按View事件

代码语言:javascript
复制
05-18 00:52:38.930 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--                                                                    
05-18 00:52:38.940 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 00:52:38.940 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_DOWN
05-18 00:52:39.440 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ---onLongClick---
05-18 00:52:39.520 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:52:39.520 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 00:52:39.520 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_UP
05-18 00:52:39.520 28522-28522/com.fang.zrf.qrcodedemo I/MainActivity: ----onClick----

如果onLongClickListener返回为false,则log如下

代码语言:javascript
复制
05-18 00:55:40.870 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:55:40.870 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 00:55:40.870 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_DOWN
05-18 00:55:41.380 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ---onLongClick---
05-18 00:55:41.760 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 00:55:41.770 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 00:55:41.770 3373-3373/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_UP

通过这些log可以看出,当activity触摸时

首先进行dispatchTounchEvent进行事件的分发,分发到view后出发onTouchListener的onTouch方法,会有三个动作,如果是长按,则在ACTION_MOVE时(如果有move)离开控件之后,在ACTION_UP之前会触发onLongClick的listener,在ACTION_UP结束后会触发onClick方法。

了解到触摸事件处理逻辑后博文刚开始的问题就好解决多了

当点击view时,只是执行onClick,而不执行onLongClick

当长按view时 ,在手抬起之前执行onLongClick,在抬起之后会执行onClick,如果想要避免onClick的执行,只需要在onLongClick方法返回true,则onClick方法不会再执行,抬起之后onTouch还是会继续执行出现ACTION_UP

代码语言:javascript
复制
05-18 23:09:29.790 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 23:09:29.790 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 23:09:29.790 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_DOWN
05-18 23:09:30.300 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ---onLongClick---
05-18 23:09:31.840 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 23:09:31.840 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 23:09:31.840 1008-1008/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_UP

但是如果onTouch方法返回true的话,那么触摸事件就不会传递给onClick或者onLongClick方法,此时就相当于只有滑动事件没有点击事件,log如下

代码语言:javascript
复制
05-18 23:11:26.150 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 23:11:26.160 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 23:11:26.160 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_DOWN
05-18 23:11:27.240 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ---dispatchTouch--
05-18 23:11:27.240 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ----onTouch---
05-18 23:11:27.240 3810-3810/com.fang.zrf.qrcodedemo I/MainActivity: ---onTouch--ACTION_UP
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档