【问题标题】:Android: Working with onTouch, onClick and onLongClick TogetherAndroid:一起使用 onTouch、onClick 和 onLongClick
【发布时间】:2014-05-04 05:26:53
【问题描述】:

在我的应用程序中,我必须将视图移动到布局上的任何位置。所以我使用了onTouchListener。在onClickonLongClick 上,我必须执行一些其他任务。我可以移动视图。但是,听众之间存在冲突。当我移动视图时,有时会调用onClickonLongClick。而且,当用户移动视图时,我不希望它们被调用。我怎样才能避免这种情况?我已经提到了这个link 来交叉检查我的代码。但是,找不到错误。以下是我的代码:

OnTouch 视图

broItemView.setOnTouchListener(new View.OnTouchListener() {
        private int deltaX;
        private int deltaY;
        private float initialTouchX;
        private float initialTouchY;
        private boolean isMoved;
        private int lastTouchX;
        private int lastTouchY;

        @Override
        public boolean onTouch(final View v, final MotionEvent event) {
            ViewGroup vg = (ViewGroup) v.getParent();
            draggedViewIndex = vg.indexOfChild(v);
            initialTouchX = event.getRawX();
            initialTouchY = event.getRawY();

            boolean result = v.onTouchEvent(event);
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                isMoved = false;
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v
                        .getLayoutParams();

                deltaX = (int) initialTouchX - params.leftMargin;
                deltaY = (int) initialTouchY - params.topMargin;
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                if (!isMoved
                                        && event.getAction() != MotionEvent.ACTION_UP) {
                                    ViewGroup vg = (ViewGroup) v
                                            .getParent();
                                    draggedViewIndex = vg.indexOfChild(v);

                                    ClipData data = ClipData.newPlainText(
                                            "", "");
                                    DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                                            v);
                                    v.startDrag(data, shadowBuilder, v, 0);
                                    v.setVisibility(View.INVISIBLE);

                                    Animation slideUp = AnimationUtils
                                            .loadAnimation(
                                                    WMMBFragmentContainerActivity.this,
                                                    R.anim.slide_up_dialog);
                                    crossImage.setVisibility(View.VISIBLE);
                                    crossImage.startAnimation(slideUp);
                                }
                            }
                        });
                    }
                }, 1000);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                Log.e(TAG, "ACTION_MOVE");
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v
                        .getLayoutParams();
                params.leftMargin = (int) initialTouchX - deltaX;
                params.topMargin = (int) initialTouchY - deltaY;
                v.setLayoutParams(params);

                isMoved = true;

                break;
            }
            case MotionEvent.ACTION_UP: {
                Log.e(TAG, "ACTION_UP");
                initialTouchX = 0;
                initialTouchY = 0;
                deltaX = 0;
                deltaY = 0;
                if (!isMoved) {
                    Log.e(TAG, "ACTION_UP if");
                    showRunningTransactionFragment(mBroList
                            .get(draggedViewIndex));
                } else {
                    Log.e(TAG, "ACTION_UP else");
                    isMoved = false;
                }
                break;
            }
            default:
                Log.e(TAG, "default");
                return result;
            }
            relBroCircle.invalidate();
            Log.e(TAG, "defaultqqq ");
            return true;
        }
    });

更新 1:

所以,根据下面 Viswanath 的建议,我修改了我的代码。但是,我仍然面临问题。当我移动onTouch 中的视图时,有时,我在处理程序中编写的代码会被执行。我不希望在用户移动视图时执行此操作。我想让它顺利成为 Facebook 信使 ChatHeads。它们的onClick or onLongClick 仅在用户想要执行它们时被调用。我不明白我在哪里犯了错误。

更新 2:

现在,我删除了多个侦听器并尝试在onTouch 中执行所有我想要的操作。它的工作除了一个问题。即使我点击视图(直到现在我还没有移动视图),ACTION_MOVE 被调用,因此isMoved 变为 true。因此,在这种情况下,ACTION_UP 中的 if block 中的代码永远不会被执行。为了查明我是否做错了什么,我创建了一个虚拟项目,选择了textview 并添加了onTouchListeneronClickListener。然后,进行点击操作。此外,我发现ACTION_MOVEonClick 之前首先被调用,然后onClick 中的代码被执行。那么,我怎样才能得到onClick 效果呢?我已经更新了我的代码。

【问题讨论】:

  • 不要设置多个监听器。最好在 onTouchListener 中处理所有这些事情
  • 按照 Viswanath 之前的建议进行了尝试,但有时,处理程序中的代码在移动视图时会被执行。我已经更新了我的代码。

标签: android ontouchlistener


【解决方案1】:

当您使用onTouch 时,可能会发生这种情况。以下是onclick的解决方法

通常我们会手动设置一个标志,比如

boolean isMoved;

case MotionEvent.ACTION_DOWN: 
    isMoved = false;

case MotionEvent.ACTION_MOVE:
    isMoved = true;

case MotionEvent.ACTION_UP:
    if(!isMoved)
       YourOnClick();

【讨论】:

  • 而且,我对 onLongClick 也有同样的作用?
  • 对于onLongClick,如果当时isMoved 为假并且用户没有执行ACTION_UP 触发器OnLongClick
  • 嗨维斯瓦纳特,我不明白你使用计时器的意义。您的意思是使用TimerTask 还是Handler。啊,我之前忘了提,这些视图是在运行时创建的。
  • 嗨@Nitish,没关系,您可以为动态创建的视图设置触摸侦听器。您可以使用处理程序,但如果您有 UI 更新,请不要忘记从 runOnUiThread() 启动侦听器
  • 嗨 Vishwanath,刚刚更新了我的代码。根据您的建议,也做了同样的事情。可以请你看一下吗?
【解决方案2】:

最后,我设法实现了我想要的。该解决方案基于上面提出的Viswanath's 想法。这是我的代码:

broItemView.setOnTouchListener(new View.OnTouchListener() {
        private int deltaX;
        private int deltaY;
        private float initialTouchX;
        private float initialTouchY;
        private boolean isMoved;
        private int lastTouchX;
        private int lastTouchY;

        @Override
        public boolean onTouch(final View v, final MotionEvent event) {
            ViewGroup vg = (ViewGroup) v.getParent();
            draggedViewIndex = vg.indexOfChild(v);
            initialTouchX = event.getRawX();
            initialTouchY = event.getRawY();
            boolean result = v.onTouchEvent(event);
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                isMoved = false;
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v
                        .getLayoutParams();

                deltaX = (int) initialTouchX - params.leftMargin;
                deltaY = (int) initialTouchY - params.topMargin;

                lastTouchX = (int) initialTouchX;
                lastTouchY = (int) initialTouchY;
                Log.e(TAG, "ACTION_DOWN lasttouchX: " + lastTouchX);
                Log.e(TAG, "ACTION_DOWN lasttouchY: " + lastTouchY);
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                if (!isMoved
                                        && event.getAction() != MotionEvent.ACTION_UP) {
                                    //perform LongClickOperation
                                }
                            }
                        });
                    }
                }, 1000);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v
                        .getLayoutParams();

                params.leftMargin = (int) initialTouchX - deltaX;
                params.topMargin = (int) initialTouchY - deltaY;

                v.setLayoutParams(params);

                break;
            }
            case MotionEvent.ACTION_UP: {

                if ((lastTouchX == (int) initialTouchX)
                        && (lastTouchY == (int) initialTouchY)) {
                    isMoved = false;
                } else if ((lastTouchX > (int) initialTouchX)) {
                    if (((lastTouchX - (int) initialTouchX) <= 10)) {
                        isMoved = false;
                    } else {
                        isMoved = true;
                    }
                } else if ((lastTouchX < (int) initialTouchX)) {
                    if ((((int) initialTouchX - lastTouchX) <= 10)) {
                        isMoved = false;
                    } else {
                        isMoved = true;
                    }
                } else if ((lastTouchY > (int) initialTouchY)) {
                    if (((lastTouchY - (int) initialTouchY) <= 10)) {
                        isMoved = false;
                    } else {
                        isMoved = true;
                    }
                } else if ((lastTouchY < (int) initialTouchY)) {
                    if ((((int) initialTouchY - lastTouchY) <= 10)) {
                        isMoved = false;
                    } else {
                        isMoved = true;
                    }
                } else {
                    isMoved = true;
                }

                if (!isMoved) {
                    //perform onClick operation
                } else {
                    isMoved = false;
                }
                initialTouchX = 0;
                initialTouchY = 0;
                deltaX = 0;
                deltaY = 0;
                break;
            }
            default:
                return result;
            }
            relBroCircle.invalidate();
            return true;
        }
    });

ACTION_UP 中,我必须添加额外的检查以确定视图是否实际移动,因为我发现即使用户只是单击了视图,ACTION_MOVE 仍会调用。正如我在帖子中提到的Update 2,我已经单独检查了这一点。而且,当我在 10" 平板电脑上测试我的代码时,我的 onclick 代码从未执行过。所以,为了避免这个问题,我不得不编写那些代码。但是,我不认为这是一个优雅的解决方案对我来说似乎是 hack。如果有人有更好的解决方案,请提出建议,以便我可以更新我的代码。

【讨论】:

  • 您有没有找到更好的解决方案来解决这个问题?
  • @MichaelAlanHuff Nops,改为使用 Android DragDrop API
猜你喜欢
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
相关资源
最近更新 更多