你如何使用MotionEvent.ACTION_POINTER_INDEX_SHIFT?

时间:2013-01-18 03:08:27

标签: android multi-touch

我一直在游戏中工作,我正在尝试制作控制器,没有太复杂的事情要做到这一点我需要跟踪2个输入(手指):1点火按钮和移动键。(向上,向下,左,右)

这是问题:手指1向下,手指2向下,手指1向上,认为是2,然后手指2向上,认为是1。

D/Controlls(18849): Action Down 1
D/Controlls(18849): Coordinates 267.7908 415.24274
D/Controlls(18849): Action Pointer Down 2
D/Controlls(18849): Coordinates 281.11423 417.23993
D/Controlls(18849): Action Pointer UP 1
D/Controlls(18849): Coordinates 272.7869 419.23718
D/Controlls(18849): Action UP 2
D/Controlls(18849): Coordinates 1148.103 439.20947

这是处理2个输入的OnTouchEvent的代码:

@Override
public boolean onTouchEvent(MotionEvent event) {
    int index = event.getActionIndex();
    int pointerId = event.getPointerId(index);
    int action = event.getActionMasked();

    int oldX, oldY;

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
        {
            hero.moveControlls((int)event.getX(), (int)event.getY());
            Log.d("Controlls", "Action Down "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
            break;
        }

        case MotionEvent.ACTION_UP:
        {
            hero.setScreenTouching(false);
            Log.d("Controlls", "Action UP "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
            break;
        }

        case MotionEvent.ACTION_POINTER_DOWN:
        {
            Log.d("Controlls", "Action Pointer Down "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());                   
            break;
        }

        case MotionEvent.ACTION_POINTER_UP:
        {
            Log.d("Controlls", "Action Pointer UP "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+  event.getY());
            break;
        }
    }
    return true;
}

现在,我查看了示例,但无法理解它们。我在API中查找了MotionEvent,它说要使用$ ACTION_POINTER_INDEX_SHIFT $,我不知道如何使用它,因为它们没有一个例子或其他东西让它更容易被理解。有关如何执行此操作的任何帮助吗?

3 个答案:

答案 0 :(得分:11)

只要辅助指针停止或向上,就会触发 ACTION_POINTER_DOWN和ACTION_POINTER_UP。如果屏幕上已有指针且新指针停止,您将收到ACTION_POINTER_DOWN而不是ACTION_DOWN。如果指针上升但仍然至少有一个触摸屏幕,您将收到ACTION_POINTER_UP而不是ACTION_UP。

ACTION_POINTER_DOWN和ACTION_POINTER_UP事件在动作值中编码额外信息。使用MotionEvent.ACTION_MASK对它进行AND运算为我们提供了动作常量,而使用 ACTION_POINTER_INDEX_MASK 对它进行AND运算可以得到指向上升或下降的指针

提取离开触摸传感器的指针索引的最佳方法。

int pointerIndex =(event.getAction()& MotionEvent.ACTION_POINTER_INDEX_MASK)>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;

我会相应更改您的代码,如下所示:

case MotionEvent.ACTION_POINTER_UP:
{
    int index = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    int pointId = event.getPointerId(index);
    Log.d("Controlls", "Action Pointer UP "+ pointerId);
    Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+  event.getY(index));
    break;
}

答案 1 :(得分:2)

我认为混淆可能是方法getX()getY()总是返回主要指针的坐标(第一个/唯一一个向下)。所以你的日志手指1中的前三个事件是主要的,然后在最后一个甚至只剩下手指2,所以它成为主要。

如果您想要正确跟踪两个手指的事件,则需要使用getX(int)getY(int);将指针索引作为参数的版本,以便您可以离散地获取每个事件中每个手指的坐标。请注意,如果每个手指以不同的顺序向下和向上变化,则每个手指的索引可能会发生变化,但是给定的手指将始终具有相同的指针ID。

一个好的方法是检查每个事件中的指针数量(例如getPointerCount())。用一根手指,索引0有效;使用两根手指,索引0和1有效。去获取每个有效指针的坐标,然后使用getPointerId()找出每个坐标对应匹配的手指。

修改

对您发布的返回右指针坐标的源代码的最简单修改是将索引添加到辅助指针的参数中,如下所示:

int index = event.getActionIndex();
int pointerId = event.getPointerId(index);
int action = event.getActionMasked();

int oldX, oldY;

switch (event.getActionMasked()) {
    case MotionEvent.ACTION_DOWN:
    {
        hero.moveControlls((int)event.getX(), (int)event.getY());
        Log.d("Controlls", "Action Down " + pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
        break;
    }

    case MotionEvent.ACTION_UP:
    {
        hero.setScreenTouching(false);
        Log.d("Controlls", "Action UP "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
        break;
    }

    case MotionEvent.ACTION_POINTER_DOWN:
    {
        Log.d("Controlls", "Action Pointer Down "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+ event.getY(index));
        break;
    }

    case MotionEvent.ACTION_POINTER_UP:
    {
        Log.d("Controlls", "Action Pointer UP "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+  event.getY(index));
        break;
    }
}

这应该使数据记录更符合您期望看到的内容。

答案 2 :(得分:0)

如果按照与按下不同的顺序发布指针(使用多点触控时可能发生的情况),上述代码可能会失败。我发现以下代码适用于3个指针,按下然后释放的顺序无关紧要:

    case MotionEvent.ACTION_UP: // for single touch
    case MotionEvent.ACTION_POINTER_UP: // when order of touch and release is the same
    case MotionEvent.ACTION_POINTER_UP + ((1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT)): // for any order of two pointers
    case MotionEvent.ACTION_POINTER_UP + ((2 << MotionEvent.ACTION_POINTER_INDEX_SHIFT)): // for any order of three pointers
    case MotionEvent.ACTION_OUTSIDE: // when moving touch out of the view
    case MotionEvent.ACTION_CANCEL: // when canceling touch (eg by home button)
    // some code to support releasing pointers
    break;

请记住 case 语句旁边必须是常量值,因此您无法根据 event.getMotion()计算值。