Понимание Android PointerID. Возвращает неожиданное значение

Недавно я получил отчет о сбое для своего приложения и, просмотрев трассировку стека, понял, что у меня проблема с мультитач-управлением.

Происходит что-то вроде этого:

Я пытаюсь записать нажатия только 4 пальцев. Больше не надо. Я хочу, чтобы все, что больше 4, эффективно «игнорировалось».

Поэтому я делаю что-то вроде этого:

@Override
public boolean onTouchEvent(MotionEvent event) {

    pointerCount = event.getPointerCount();

    if (pointerCount <= 4){

    actionMask = event.getActionMasked();
    pointerIndex = event.getActionIndex();      
    pointerID = event.getPointerId(pointerIndex);
    //etc.............

Поэтому я ничего не запускаю в onTouch, если опущено более 4 пальцев.

Кажется, это работает нормально, обычно оно не «действует» на палец 5, 6 и т. Д. Так что все в порядке. (Я говорю «обычно» из-за того, что следует далее).....

Проблема

Однако, если я положу, скажем, 6 пальцев вниз, а затем подниму их, указатель указателя на последний опущенный палец будет равен 5. На самом деле это не проблема, поскольку я ничего не делаю в action_up. или action_pointer_up.

Однако в action_pointer_down в 90 % случаев я получаю ожидаемое поведение, когда любой палец, помещенный вниз, имеет идентификатор от 0 до 3.

Однако если вы поместите 5 или более пальцев на экран и быстро коснетесь экрана снова и снова, в конечном итоге событию action_pointer_down будет присвоен идентификатор, равный 4 или больше (я видел 4, 5, 6 и 7). Поэтому, когда он пытается поместить эти значения в массивы xList nad yList, он вылетает с исключением вне границ.

Это проблема, потому что в action_pointer_down я сохраняю x и y пальца в паре созданных мной массивов. (Мне нужна эта информация для выполнения некоторых действий позже) Эти массивы имеют размер 4 каждый (таким образом, индексы от 0 до 3). Как это:

case MotionEvent.ACTION_POINTER_DOWN:{

    try{                        
            if (isJumpPressed(event.getX(pointerIndex),event.getY(pointerIndex))){
                 //Jump here
            }


            else if (isLeftPressed(event.getX(pointerIndex),event.getY(pointerIndex))){
                 //Move left here
            }

            else if(isRightPressed(event.getX(pointerIndex),event.getY(pointerIndex))){
                //Move right here
            }

                //****These lines randomly fail if the pointerID >=4
                xList[pointerID]=event.getX(pointerIndex);
                yList[pointerID]=event.getY(pointerIndex);

    }
    catch(Exception e){                         
        Log.v("Error","Oops, something's wrong");                   
    }

    break;

    }

}

Почему это? Это ошибка в Multi-touch API или я чего-то не понимаю. При обычном использовании ошибка обычно не возникает, но я могу легко вызвать ее сам, и она будет обнаружена пользователем, поэтому любая помощь будет оценена по достоинству. Я ожидаю, что любое событие с опущенным пальцем будет получать только идентификатор 0-3. Если только я что-то не так понял.


person Zippy    schedule 25.12.2014    source источник


Ответы (1)


Не полагайтесь на то, что идентификатор указателя является последовательным или вообще напрямую связан с количеством указателей, которые в данный момент касаются экрана. Идентификатор — это идентификатор, а не способ определить, сколько пальцев опущено или какие пальцы опущены.

В документации указано, что идентификатор будет просто значение от 0 до getPointerCount() - 1 и что идентификатор используется в определенном жесте. Таким образом, если Android интерпретирует ваше быстрое касание как один жест, несколько касаний одним и тем же пальцем могут иметь разные идентификаторы.

В вашем конкретном случае похоже, что Map<int, float> может лучше работать для сопоставления определенных указателей с их координатами X и Y. Использование карты, безусловно, исправит ваше исключение за пределами границ.

Например:

Map<Integer, Float> xMap = new HashMap<>();
// ...

case MotionEvent.ACTION_POINTER_DOWN: 
    // ...

    xMap.put(pointerID, event.getX(pointerIndex);

Позже вы можете получить значение, скажем, для указателя с ID 2 с помощью xMap.get(2).

person Bryan Herbst    schedule 25.12.2014
comment
Привет @Tania.7x - спасибо. Я понимаю. Не могли бы вы привести пример использования карты? Также можете ли вы предусмотреть решение, в котором я могу использовать предопределенный массив? Я говорю это, потому что, насколько я понимаю, Map использует итератор и выделяет память при доступе к ней. Спасибо за вашу помощь!! - person Zippy; 25.12.2014
comment
Обычно вы не перебираете карту, хотя, конечно, можете, если хотите. Карта полезна, когда у вас есть элементы с определенным ключом (например, идентификатор), но у вас нет гарантии, что эти ключи будут в каком-то определенном порядке или не будут последовательными. - person Bryan Herbst; 25.12.2014