Понимание 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 пальцами вниз, а затем подниму их, последний из помещенных вниз имеет указатель ID, равный 5. На самом деле это не проблема, поскольку я ничего не делаю в action_up или action_pointer_up.
Однако в action_pointer_down 90% времени я получаю ожидаемое поведение, когда любой палец, помещенный вниз, имеет идентификатор от 0 до 3.
Однако, если вы поместите 5 или более пальцев на экран и быстро нажмете на экран снова и снова, в конце концов, событию action_pointer_down будет присвоено значение 4 или более (я видел 4, 5, 6 и 7) Поэтому, когда он пытается поместить эти значения в массивы xList и nList, он вылетает с исключением вне границ.
Это проблема, потому что в 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 или я чего-то не понимаю. При нормальном использовании ошибка обычно не возникает, но я могу легко вызвать ее самостоятельно, и она будет найдена пользователем, поэтому любая помощь будет принята с благодарностью. Я ожидал бы, что любое событие с опущенным пальцем когда-либо получит только ID 0-3. Если я что-то не так понял.
1 ответ
Не полагайтесь на то, что идентификатор указателя является последовательным или вообще напрямую связан с количеством указателей, которые в данный момент касаются экрана. Идентификатор - это идентификатор, а не способ определить, сколько пальцев опущено или какие пальцы опущены.
В документации говорится, что ID будет просто значением от 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);
Позже вы можете получить значение, скажем, для указателя с идентификатором 2 с помощью xMap.get(2)
,