android的弹出菜单,使用activity来实现,但是长按的时间太短,容易与其他view的触摸逻辑相冲突,代码如下

 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_draw);        //其他代码        _view.setOnCreateContextMenuListener(this);    }    @Override    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {        menu.add(1, 10001, 0, "添加");        menu.add(1, 10002, 1, "删除");        menu.add(1, 10003, 2, "切换");        super.onCreateContextMenu(menu, v, menuInfo);    }    @Override    public boolean onContextItemSelected(MenuItem item) {        switch (item.getItemId()) {            case 10001: {                //添加                break;            }            case 10002: {                //删除                break;            }            case 10003: {                //切换;                break;            }            default:                break;        }        return super.onContextItemSelected(item);    }

为此,我们需要对长按进行额外的处理,于是需要对_view的onTouch事件进行相应的处理,为了便于调用,将长按的检测逻辑封装成了相应的类,代码如下

/**     * 长按工作器     */    class  LongTouchWorker{        /**         * 长按时两次点差的最大偏移量,超过此偏移量则不是长按         */        private int _longTouchOffset = 50;        private int _lastMotionX;        private int _lastMotionY;        private int _longTouchDelay_ms;        private LongTouchCallback _longTouchCallback=null;        public LongTouchWorker(int longTouchDelay_ms,LongTouchCallback longTouchCallback){            _longTouchDelay_ms =longTouchDelay_ms;            _longTouchCallback=longTouchCallback;        }        private Handler _longTouchHandle=new Handler(){            @Override            public void handleMessage(Message msg) {                super.handleMessage(msg);                Log.d(TAG,"LongTouchHandle");            }        };        private Runnable _longTouchRunnable=new Runnable() {            @Override            public void run() {                if(_longTouchCallback!=null)                {                    _longTouchCallback.longTouch(_lastMotionX,_lastMotionY);                }            }        };        public void onTouch(View v, MotionEvent event) {            int x = (int) event.getX();            int y = (int) event.getY();            int pointerCount = event.getPointerCount();            if(pointerCount>1){                //多点触控,直接取消长按                cancelLongTouch();            }            else {                switch (event.getAction()) {                    case MotionEvent.ACTION_UP:                        // 弹起时,移除已有Runnable回调,弹起就算长按结束了(不需要考虑用户是否长按了超过预设的时间)                        cancelLongTouch();                        Log.d(TAG, "LongTouch UP");                        break;                    case MotionEvent.ACTION_MOVE:                        if (Math.abs(_lastMotionX - x) > _longTouchOffset                                || Math.abs(_lastMotionY - y) > _longTouchOffset) {                            // 移动误差阈值                            // xy方向判断                            // 移动超过阈值,则表示移动了,就不是长按(看需求),移除 已有的Runnable回调                            cancelLongTouch();                        }                        Log.d(TAG, "LongTouch Move");                        break;                    case MotionEvent.ACTION_DOWN:                        // 每次按下重新计时                        // 按下前,先移除 已有的Runnable回调,防止用户多次单击导致多次回调长按事件的bug                        cancelLongTouch();                        _lastMotionX = x;                        _lastMotionY = y;                        // 按下时,开始计时                        _longTouchHandle.postDelayed(_longTouchRunnable, _longTouchDelay_ms);                        Log.d(TAG, "LongTouch Down");                        break;                }            }        }        private void cancelLongTouch(){            _longTouchHandle.removeCallbacks(_longTouchRunnable);            if(_longTouchCallback!=null){                _longTouchCallback.cancelLongTouch();            }        }    }    /**     * 长按的回调     */    public interface LongTouchCallback{        /**         * 取消长按         */        void cancelLongTouch();        /**         * 长按         */        void longTouch(int x,int y);    }

在LongTouchWorker中通过onTouch的检测来判断是否为长按,判断过程要注意几点

1.弹起(UP)、按下(DOWN)、移动(MOVE)的逻辑,尤其是MOVE时要设置感应的偏移量,因为手指按下时,点的位置是有可能偏移的。

2.Handle和Runnable的配合,remove和postDelay的控制

3.通过接口LongTouchCallback来回调,触发相应的longTouch和cancelLongTouch事件。

那要如何使用LongTouchWorker呢?假如我们的view是自定义的,比如LongTouchView,在LongTouchView的onTouch事件调用LongTouchWorker,示例代码如下

/** * 自定义LongTouchView */public class LongTouchView extends View { private LongTouchWorker _longTouchWorker=null;  /**     * 设置长按工作器     * @param longTouchDelay_ms 长按的延迟时间(毫秒)     * @param longTouchCallback 长按的回调     */    public void set_longTouchWorker(int longTouchDelay_ms,LongTouchCallback longTouchCallback){        _longTouchWorker=new LongTouchWorker(longTouchDelay_ms,longTouchCallback);    }@Override    public boolean onTouchEvent(MotionEvent event) {       if( _longTouchWorker!=null)        {            _longTouchWorker.onTouch(this,event);        }        return super.onTouchEvent(event);    }}

有了LongTouchWorker之后,我们就可以解决前面弹出菜单时,长按时间太短的问题,示例代码如下

  _longTouchView.set_longTouchWorker(_longTouchDelay_ms, new LongTouchCallback() {            @Override            public void cancelLongTouch() {            }            @Override            public void longTouch(int x, int y) {                showPopupMenu(x, y);            }        });

对于showPopupMenu弹出菜单的位置控制,可以参看《PopupMenu弹出位置的控制》

更多相关文章

  1. Android发送短信功能代码
  2. [置顶] Android源代码下载
  3. Android 代码混淆 选项说明
  4. 反抗金山毒霸的代码
  5. Android应用程序组件Content Provider的启动过程源代码分析(2)
  6. android开发之res下的menu (xml+代码的形式)
  7. 【源代码】一键分享各个社交平台_android
  8. Android常用框架混淆代码
  9. Android之GLES2.0显示图片测试代码

随机推荐

  1. 获取资源的id
  2. Android请不要滥用SharedPreference
  3. Android系统设计中存在设计模式分析
  4. Android第一个功能:手机拨号器
  5. Android 颜色渲染(十) ComposeShader组合
  6. Android快速入门相关(一)
  7. Android 基础UI编程1
  8. Android 代码执行Linux Shell小记
  9. 深入浅出 - Android系统移植与平台开发(九
  10. Android基于OpenSL ES的音频播放