Android ACTION_MOVE Threshold
Я пишу приложение, которое включает в себя запись на экране с помощью пальца или, в конечном итоге, стилуса. У меня эта часть работает. На ACTION_DOWN начинает рисовать; в ACTION_MOVE добавляет линейные сегменты; на ACTION_UP, заканчивает линию.
Проблема заключается в том, что после ACTION_DOWN, по-видимому, указатель должен переместиться более чем на 10 пикселей от места его начала (в основном это поле 20x20 вокруг начальной точки), чтобы начать отправку событий ACTION_MOVE. После того, как вы покинули коробку, все события перемещения достаточно точны. (Я выяснил, что такое 10-пиксельное изображение, протестировав его.) Поскольку оно предназначено для письма или рисования, 10-пиксельная потеря - это довольно существенная потеря: в зависимости от того, насколько мелким вы пытаетесь написать, вы можете потерять первую букву. или два Я ничего не смог найти по этому поводу - только пара сообщений на форуме или два, например http://android.modaco.com/topic/339694-touch-input-problem-not-detecting-very-small-movements/page__pid__1701028. Кажется, он присутствует на некоторых устройствах или системах, а не на других. Хотя нет идей, как избавиться от него, когда он у вас есть.
Я использую Galaxy Tab 10.1, с Android 3.1. Я попробовал несколько разных вещей, чтобы попытаться избавиться от этого: я попытался установить координаты события на что-то другое, чтобы посмотреть, смогу ли я обмануть его, думая, что курсор находится в другом месте; Я попытался повторно отправить событие с измененными координатами (мой обработчик реагировал на новые точки, но все еще не реагировал на движения в радиусе 10 пикселей.) Я искал в исходном коде любые ссылки на эффект, и не нашел (хотя я думаю, что это из другой версии Android - код для 3.1 еще не выпущен, не так ли?) Я искал способы запроса текущего состояния указателей, поэтому я мог бы просто иметь таймер ловить изменения, пока указатель не переступит порог. Не удалось найти способ получения координат указателя без соответствующего события движения. Ничего не сработало. Кто-нибудь знает что-нибудь об этом, или есть какие-либо идеи или обходные пути? Спасибо.
- Обновление: события перетаскивания показывают одинаковый порог.
3 ответа
Я частично согласен с постом @passsy, но пришел к другому выводу. Во-первых, как уже упоминалось, mTouchSlop
это значение, которое нас интересует и выставляется через ViewConfiguration.get(context).getScaledTouchSlop();
Если вы проверяете источник Android для ViewConfiguraton, значением по умолчанию для TOUCH_SLOP является 8dip, но в комментариях упоминается, что это значение является только запасным, и фактическое значение определяется при сборке ОС Android для этого конкретного устройства. (может быть больше или меньше, чем это значение. Похоже, что это справедливо для устройств Galaxy Tab)
Более конкретный пример кода, mTouchSlop
значение читается из ViewConfiguration
когда View
инициализируется, но значение доступно только в onTouchEvent
метод. Если вы продлите View
и переопределить этот метод (без вызова super
) то поведение mTouchSlop
в View
класс больше не актуален.
Более показательным (для нас) было то, что при изменении настроек Android для наложения событий касания на экране касание с небольшим перетаскиванием не регистрируется как событие движения, что подчеркивается тем фактом, что перекрестие из ОС Android не перемещается. Исходя из этого, мы заключаем, что минимальное расстояние перетаскивания применяется на уровне операционной системы, и ваше приложение никогда не узнает о событиях перетаскивания, меньших, чем значение TOUCH_SLOP. Вы также должны знать, что TOUCH_SLOP не должен использоваться напрямую, и API не поддерживает getTouchSlop
метод и рекомендует getScaledTouchSlop
который принимает во внимание размер экрана устройства и плотность пикселей. Побочным эффектом этого является то, что фактическая минимальная длина хода, воспринимаемая на разных устройствах, может варьироваться. например, на Galaxy Tab 2.0 7.0 "создается впечатление, что мы можем рисовать минимальные штрихи, используя ту же кодовую базу, что и при работе на Galaxy Tab 2.0 10.1"
Вам также следует помнить, что (если вы найдете способ изменить это значение), это значение определяет, как системы Android различают нажатия и удары. То есть, если вы нажмете на экран, но при выполнении касания ваш палец будет слегка двигаться, он будет интерпретироваться как касание, если оно перемещалось меньше, чем TOUCH_SLOP, но как удар, если оно перемещалось больше, чем TOUCH_SLOP. Поэтому установка меньшего значения TOUCH_SLOP увеличит вероятность того, что касание будет интерпретировано как штрих.
Наш собственный вывод состоит в том, что это минимальное расстояние - это не то, что можно изменить на практике, и это то, с чем нам нужно жить.
Проблема в линии 6549 в классе View https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java
if (!pointInView(x, y, mTouchSlop)) {...}
/**
* Utility method to determine whether the given point, in local coordinates,
* is inside the view, where the area of the view is expanded by the slop factor.
* This method is called while processing touch-move events to determine if the event
* is still within the view.
*/
private boolean pointInView(float localX, float localY, float slop) {
return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
localY < ((mBottom - mTop) + slop);
}
mTouchSlop устанавливается в конструкторе
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Вы можете расширить View и установить mTouchSlop на ноль. Я не вижу другого способа установить mTouchSlop. Там нет функции, как getApplicationContext.setScaledTouchSlop(int n)
,
Расширьте View Class.
Переопределите метод pointInView без аннотации "@Override" и установите touchSlop = 0:
public boolean pointInView(float localX, float localY, float slop) {
slop = 0;
return localX >= -slop && localY >= -slop && localX < (getWidth() + slop) &&
localY < (getBottom() + slop);
}