Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
В этом разделе показано, как отслеживать события касания с нескольких пальцев
Иногда требуется отслеживать отдельные пальцы при одновременном перемещении на экране. Одно из типичных приложений — это программа с пальцем. Вы хотите, чтобы пользователь мог рисовать с одним пальцем, а также рисовать с несколькими пальцами одновременно. При обработке нескольких сенсорных событий программа должна различать, какие события соответствуют каждому пальцу. Android предоставляет код идентификатора для этой цели, но получение и обработка этого кода может быть немного сложной.
Для всех событий, связанных с определенным пальцем, код идентификатора остается неизменным. Код идентификатора назначается, когда пальцем сначала прикасается к экрану, и становится недействительным после того, как палец поднимается с экрана. Эти коды идентификаторов обычно являются очень небольшими целыми числами, и Android повторно использует их для последующих событий касания.
Почти всегда программа, которая отслеживает отдельные пальцы, поддерживает словарь для отслеживания сенсорного ввода. Ключ словаря — это код идентификатора, определяющий определенный палец. Значение словаря зависит от приложения. В примере FingerPaint каждый штрих пальца (от касания к выпуску) связан с объектом, который содержит все сведения, необходимые для отрисовки линии, нарисованной с помощью этого пальца. Программа определяет небольшой FingerPaintPolyline класс для этой цели:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new Path();
}
public Color Color { set; get; }
public float StrokeWidth { set; get; }
public Path Path { private set; get; }
}
Каждая полилайн имеет цвет, ширину штриха и графический Path объект Android для накапливания и отрисовки нескольких точек линии по мере рисования.
Оставшаяся часть кода, показанная ниже, содержится в производном именованном ViewFingerPaintCanvasViewкоде. Этот класс поддерживает словарь объектов типа FingerPaintPolyline во время их активного рисования одним или несколькими пальцами:
Dictionary<int, FingerPaintPolyline> inProgressPolylines = new Dictionary<int, FingerPaintPolyline>();
Этот словарь позволяет представлению быстро получать FingerPaintPolyline сведения, связанные с определенным пальцем.
Класс FingerPaintCanvasView также поддерживает List объект для завершенных полилайнов:
List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();
Объекты в этом List порядке находятся в том же порядке, что и они были нарисованы.
FingerPaintCanvasView переопределяет два метода, определенных в следующих Viewметодах: OnDraw и OnTouchEvent.
В его OnDraw переопределении представление рисует завершенные полилайны, а затем рисует выполняемые полилайны.
Переопределение OnTouchEvent метода начинается с получения pointerIndex значения из ActionIndex свойства. Это ActionIndex значение отличается от нескольких пальцев, но оно не согласовано в нескольких событиях. По этой причине используется pointerIndex для получения значения указателя id из GetPointerId метода. Этот идентификатор согласован в нескольких событиях:
public override bool OnTouchEvent(MotionEvent args)
{
// Get the pointer index
int pointerIndex = args.ActionIndex;
// Get the id to identify a finger over the course of its progress
int id = args.GetPointerId(pointerIndex);
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
// ...
}
// Invalidate to update the view
Invalidate();
// Request continued touch input
return true;
}
Обратите внимание, что переопределение использует ActionMasked свойство в switch инструкции, а не Action свойство. Для этого есть следующие причины.
При работе с несколькими сенсорными Action экранами свойство имеет значение MotionEventsAction.Down для первого пальца, чтобы коснуться экрана, а затем значения Pointer2Down и Pointer3Down как второй и третий пальцы также касаются экрана. Как четвертый и пятый пальцы делают контакт, свойство имеет числовые значения, Action которые даже не соответствуют членам MotionEventsAction перечисления! Необходимо проверить значения битовых флагов в значениях, чтобы интерпретировать то, что они означают.
Аналогичным образом, как пальцы покидают контакт с экраном, Action свойство имеет значения Pointer2Up и Pointer3Up для второго и третьего пальцев, а Up также для первого пальца.
Свойство ActionMasked занимает меньшее количество значений, так как оно предназначено для использования в сочетании со ActionIndex свойством для различения нескольких пальцев. Когда пальцы касаются экрана, свойство может быть равно MotionEventActions.Down только первому пальцу и PointerDown последующим пальцам. По мере того как пальцы покидают экран, ActionMasked имеют значения Pointer1Up для последующих пальцев и Up для первого пальца.
При использовании ActionMasked, ActionIndex различает следующие пальцы для касания и выхода из экрана, но обычно не нужно использовать это значение, за исключением аргумента других методов в объекте MotionEvent . Для нескольких касаний один из наиболее важных из этих методов вызывается GetPointerId в приведенном выше коде. Этот метод возвращает значение, которое можно использовать для ключа словаря для связывания определенных событий с пальцами.
Переопределение OnTouchEvent в примере обрабатывает MotionEventActions.Down и PointerDown события идентично путем создания нового FingerPaintPolyline объекта и добавления его в словарь:
public override bool OnTouchEvent(MotionEvent args)
{
// Get the pointer index
int pointerIndex = args.ActionIndex;
// Get the id to identify a finger over the course of its progress
int id = args.GetPointerId(pointerIndex);
// Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
// Create a Polyline, set the initial point, and store it
FingerPaintPolyline polyline = new FingerPaintPolyline
{
Color = StrokeColor,
StrokeWidth = StrokeWidth
};
polyline.Path.MoveTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
inProgressPolylines.Add(id, polyline);
break;
// ...
}
// ...
}
Обратите внимание, что он pointerIndex также используется для получения положения пальца в представлении. Все сенсорные данные связаны со значением pointerIndex . Уникально id идентифицирует пальцы между несколькими сообщениями, поэтому используется для создания записи словаря.
OnTouchEvent Аналогичным образом переопределение также обрабатывает MotionEventActions.Up и Pointer1Up идентично путем передачи завершенной полилайн в completedPolylines коллекцию, чтобы они могли быть нарисованы во время OnDraw переопределения. Код также удаляет id запись из словаря:
public override bool OnTouchEvent(MotionEvent args)
{
// ...
switch (args.ActionMasked)
{
// ...
case MotionEventActions.Up:
case MotionEventActions.Pointer1Up:
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
// Transfer the in-progress polyline to a completed polyline
completedPolylines.Add(inProgressPolylines[id]);
inProgressPolylines.Remove(id);
break;
case MotionEventActions.Cancel:
inProgressPolylines.Remove(id);
break;
}
// ...
}
Теперь для сложной части.
Между событиями вниз и вверх, как правило, есть много MotionEventActions.Move событий. Они упаковываются в один вызов OnTouchEvent, и они должны обрабатываться по-разному от Down событий и Up событий. Значение, полученное pointerIndexActionIndex ранее из свойства, должно игнорироваться. Вместо этого метод должен получить несколько pointerIndex значений, циклив между 0 и PointerCount свойством, а затем получить id для каждого из этих pointerIndex значений:
public override bool OnTouchEvent(MotionEvent args)
{
// ...
switch (args.ActionMasked)
{
// ...
case MotionEventActions.Move:
// Multiple Move events are bundled, so handle them differently
for (pointerIndex = 0; pointerIndex < args.PointerCount; pointerIndex++)
{
id = args.GetPointerId(pointerIndex);
inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
args.GetY(pointerIndex));
}
break;
// ...
}
// ...
}
Этот тип обработки позволяет образцу отслеживать отдельные пальцы и выводить результаты на экране:
Теперь вы узнали, как можно отслеживать отдельные пальцы на экране и различать их.