Android ACTION_MOVE Threshold - PullRequest
       40

Android ACTION_MOVE Threshold

12 голосов
/ 22 июля 2011

Я пишу приложение, которое включает в себя запись на экране одним пальцем или, в конечном итоге, стилусом.У меня эта часть работает.На 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#entry1701028. Похоже, он присутствует на некоторых устройствах или системах, а не на других.Хотя нет идей, как избавиться от него, когда он у вас есть.

Я использую Galaxy Tab 10.1 с Android 3.1.Я попробовал несколько разных вещей, чтобы попытаться избавиться от этого: я попытался установить координаты события на что-то другое, чтобы посмотреть, смогу ли я обмануть его, думая, что курсор находится в другом месте;Я попытался повторно отправить событие с измененными координатами (мой обработчик реагировал на новые точки, но все еще не реагировал на движения в радиусе 10 пикселей.) Я искал в исходном коде любые ссылки на эффект,и не нашел (хотя я думаю, что это из другой версии Android - код для 3.1 еще не выпущен, не так ли?) Я искал методы запроса текущего состояния указателей, так что я мог бы просто иметь таймерловить изменения, пока указатель не переступит порог.Не удалось найти способ получения координат указателя без соответствующего события движения.Ничего не получалось.Кто-нибудь знает что-нибудь об этом, или есть какие-либо идеи или обходные пути?Спасибо.

- Обновление: события перетаскивания показывают одинаковый порог.

Ответы [ 3 ]

23 голосов
/ 14 марта 2013

Я частично согласен с постом @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 на меньшее значение увеличит вероятность того, что отвод будет интерпретирован как штрих.

Наш собственный вывод состоит в том, что это минимальное расстояние не может быть изменено на практикеи нам нужно с этим жить.

4 голосов
/ 13 января 2012

Проблема в строке 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).

1 голос
/ 16 августа 2018

Расширить класс представления.

Переопределить метод 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);
}
...