如何在允许子视图处理点击的同时移动ViewGroup?

时间:2017-10-16 12:15:49

标签: android

FrameLayout封装了两个ImageView。这就是我想要的:

在用户触摸和拖动时移动整个布局,但是当有点击时,应由个别ImageView处理(通过各自的View.OnClickListener())< / em>的

当前行为:目前,当我尝试拖动视图组时,它会随机跳转一次(每个拖动事件),然后开始用手指移动。所以,就像你将手指移到视图组之外并且它正在移动。

其次,没有点击事件被路由到孩子ImageView

我尝试了什么:

我尝试扩展封装FrameLayout s的<{1}}:

ImageView

那么,这段代码有什么问题?

2 个答案:

答案 0 :(得分:1)

首先,getRawX()的结果被转换为屏幕0,0,getX()相对于它自己的视图。

此外,initialX和getCurrentX的累积量将只是拖动的值,你需要存储屏幕x并使用它拖动或计算ACTION_MOVE的每个差异并使用它

            //remember the initial position
            initialTouchX = event.getX();
            initialTouchY = event.getY();
            screenX = getX();
            screenY = getY();

然后ON_MOVE

            setX(screenX + event.getX() - initialTouchX);
            setY(screenY + event.getY() - initialTouchY);

其次,你必须调用super.onTouchEvent(MotionEvent.obtain(event))或super.dispatchTouchEvent作为onTouchEvent的第一行,因为你的视图正在消耗所有事件。

答案 1 :(得分:0)

事实证明这比我预期的要简单得多(见下面评论中的解释):

react-native run-android

这个解决方案有一个警告:点击事件完全基于移动的距离。通常,要区分点击和长按,您还可以执行this之类的操作:

@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // The plan is to intercept the events here and if,
        // 1) The move is an ACTION_DOWN, return false indicating we want more events
        // to be able to ascertain if we want this ViewGroup to move or the children
        // views to handle the click event.
        // 2) On receiving the ACTION_MOVE, of course, move the ViewGroup but the sure short
        // indication of click would be to check it for in ACTION_DOWN with threshold of 5px.
        // In that case, we would return super.onInterceptTouchEvent(event); meaning, let the
        // event handling happen normally without interception
        // (Remember - the ACTION_DOWN had been recorded by the children previously when we
        // returned false and on receiving the ACTION_UP, it would constitute the complete event)
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:

                // remember the initial position
                initialTouchX = event.getX();
                //Log.d(TAG, "onInterceptTouchEvent().ACTION_DOWN.initialTouchX: " + initialTouchX);
                initialTouchY = event.getY();
                //Log.d(TAG, "onInterceptTouchEvent().ACTION_DOWN.initialTouchY: " + initialTouchY);
                return false;

            case MotionEvent.ACTION_UP:
                int xDiff = (int) (event.getX() - initialTouchX);
                int yDiff = (int) (event.getY() - initialTouchY);


                //The check for Xdiff <5 && YDiff< 5 because sometime elements moves a little while clicking.
                //So that is click event.
                if (xDiff < 5 && yDiff < 5) {
                    return super.onInterceptTouchEvent(event);
                }
                return false;

            case MotionEvent.ACTION_MOVE:

                int moveX = (int) (event.getX() - initialTouchX + getX());
                int moveY = (int) (event.getY() - initialTouchY + getY());

                setX(moveX);
                setY(moveY);

                //Update the layout with new X & Y coordinate
                invalidate();
        }
        return false;

    }

P.S:在提供的解决方案中无需覆盖private long lastTouchDown; private static int CLICK_ACTION_THRESHHOLD = 200; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastTouchDown = System.currentTimeMillis(); break; case MotionEvent.ACTION_UP: if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD) { Log.w("App", "You clicked!"); } break; } return true; } 方法。