zoukankan      html  css  js  c++  java
  • 为自定义的View添加长按事件

    以前开发画板组件时,要添加一个长按监听事件,这个画板实际上就是继承自View的一个自定义组件。

    首先,设置好长按事件发生时要触发的操作:

      private class LongPressRunnable implements Runnable {
    
            private int x, y;
    
            public void setPressLocation(float x, float y) {
                this.x = (int) x;
                this.y = (int) y;
            }
    
            @Override
            public void run() {
                Log.i("发生长按事件,位置在:" + x + "、" + y);
            }
    
        }

    接下来,编写自定义的View,重点在覆写dispatchTouchEvent(MotionEvent)方法:

    public class MyView extends View {
    
            ...
    
        /**
         * 当长按事件发生时,要触发的任务
         */
        private LongPressRunnable longPressRunnable = new LongPressRunnable();
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
    
            if (longPressRunnable != null) {
    
                //TODO 这里可以增加一些规则,比如:模糊XY的判定,使长按更容易触发
    
                removeCallbacks(longPressRunnable);
    
                if (event.getAction() == MotionEvent.ACTION_DOWN
                        && event.getPointerCount() == 1) {
                    postCheckForLongTouch(event.getX(), event.getY());
                }
            }
    
            return true;
        }
    
        private void postCheckForLongTouch(float x, float y) {
    
            longPressRunnable.setPressLocation(x, y);
           postDelayed(longPressRunnable,
    500); } }

    原理很简单,长按事件的本质是:手指触摸某个点保持不移动,也就是touch的时候仅仅发生ACTION_DOWN事件,不发生ACTION_MOVE和ACTION_UP事件,这样经过一定时间(这里是500毫秒)则成功触发长按事件。

    所以一个长按事件的周期是On Touch Down ---> 500ms ---> On Long Press。

    接下来分析上面的实现:当我们收到Touch事件时,不管是什么事件,先删除上一次设置好的longPressRunnable,

    removeCallbacks(longPressRunnable);

    这意味着上一次触摸周期没有触发长按操作。

    然后判断事件类型,如果是“单指ACTION_DOWN”事件则表明有可能会触发长按操作,那么我们通过View.postDelayed()方法将longPressRunnable放进这个View所在线程的任务队列中,并延迟500毫秒执行,

    if (event.getAction() == MotionEvent.ACTION_DOWN && event.getPointerCount() == 1) {
         postCheckForLongTouch(event.getX(), event.getY());
    }
    private void postCheckForLongTouch(float x, float y) {
        longPressRunnable.setPressLocation(x, y);
        postDelayed(longPressRunnable, 500);
    }

    如果在这500毫秒内,用户的手指没有移动或抬起,也就是不会有任何touch事件到来,则该longPressRunnable会在500毫秒后运行,一个长按操作就完成了。

    如果在这500毫秒内用户的手指移动或抬起了,那么新的touch事件到来,longPressRunnable也会被移除。

    以上就是整个实现,这个实现有个需要优化的地方,就是//TODO那里,由于人的手指并没有那么精细,在长按过程中可能会有一点移动,这往往会导致长按失败,所以我们可以在//TODO那里添加对ACTION_MOVE事件的处理,忽略一些细微的移动事件,留给读者自行实现吧:D

  • 相关阅读:
    自定义TextInput中displayAsPassword的字符
    C#序列化与反序列化代码记录
    解决Discuz!NT"Code: 100, Message: 指定..."问题
    如何在asp.net项目开发的验证码图片和打印中区别0和O(零和字母O)
    "淘宝开放平台"可以成为程序员的摇钱树吗?
    Discuz!NT与asp.net整合集成实例教程
    最震撼的大片《2012》世界末日 电影 高画质 超DVD版清晰效果 在线视频播
    划时代的感人大片!《机器人总动员》(WALL.E) 在线播放
    从数据库某表转换并导入数据到另一表
    界面原型设计工具选择报告
  • 原文地址:https://www.cnblogs.com/coding-way/p/3558050.html
Copyright © 2011-2022 走看看