Обработка событий сенсорной панели
Когда пользователи касаются и шевелят пальцами на сенсорных панелях MacBook Air и более свежих моделях MacBook Pro, OS X генерирует мультисенсорные события, события жеста и события от нажатия мыши. Аппаратные средства сенсорной панели включают встроенную поддержку интерпретации общих жестов и отображения перемещений пальца к событиям от нажатия мыши. Кроме того, операционная система обеспечивает обработку по умолчанию жестов; можно наблюдать, как OS X обрабатывает эти жесты в системном предпочтении Сенсорной панели. Можно также создать приложения, получающие и реагирующие на жесты и мультисенсорные события отличительными способами.
Приложение не должно полагаться на событие жеста или сенсорную обработку событий как единственный механизм для интерпретации пользовательских действий ни для какой критической функции. Пользователи могли использовать настольный компьютер или, если они используют ноутбук, не мог бы использовать сенсорную панель вообще — например, им можно было включить мышь USB ноутбук. Функции сенсорного события должны дополнить стандартный способ передать пользовательские команды.
События жеста являются разновидностью мультисенсорных событий, потому что они основываются на интерпретации последовательности касаний. Другими словами, жесты являются серией мультисенсорных событий, распознанных сенсорной панелью как образование жеста. Жесты и сенсорные события требуют, чтобы Вы приняли другой подход для обработки их. Для понимания этих подходов, полезно знать, как и когда события сгенерированы, как они поставлены приложению, и какую информацию они содержат о фактических касаниях к сенсорной панели.
Жесты являются Сенсорными Перемещениями, Интерпретируемыми Сенсорной панелью
Жесты являются определенными перемещениями пальцев на сенсорной поверхности, такими как сенсорная панель, которые имеют стандартное значение. Драйвер сенсорной панели интерпретирует три из этих перемещений как определенные жесты:
Зажимание перемещений (в или) является жестами, означающими уменьшение или увеличение (также названный увеличением).
Два пальца, перемещающиеся в противоположные полукруги, являются жестом, означающим, вращаются.
Три рисования кистью пальцев через поверхность сенсорной панели в общем направлении являются сильно ударить жестом.
Два пальца, перемещающиеся вертикально или горизонтально, являются жестом прокрутки.
Система поставляет низкоуровневые события, представляющие определенные жесты активному приложению, где они упаковываются как NSEvent
объекты и помещенный в очередь событий приложения. Они продвигаются тот же путь как события от нажатия мыши для поставки представлению под указателем мыши. NSWindow
объект поставляет событие жеста представлению путем вызова надлежащего NSResponder
метод для жеста: magnifyWithEvent:
, rotateWithEvent:
, или swipeWithEvent:
. Если представление не обрабатывает жест, оно перемещается цепочка респондента, пока другой объект не обрабатывает его или пока оно не отбрасывается.
Типы событий жеста и последовательностей жеста
Платформа AppKit, в NSEvent.h
, объявляет NSEventType
константы для жестов, показанных в Перечислении 8-2.
Константы перечисления 8-1 для событий жеста в платформе AppKit
NSEventTypeGesture = 29, |
NSEventTypeMagnify = 30, |
NSEventTypeSwipe = 31, |
NSEventTypeRotate = 18, |
NSEventTypeBeginGesture = 19, |
NSEventTypeEndGesture = 20 |
Как пользователи касаются и шевелят пальцами через сенсорную панель, драйвер сенсорной панели генерирует последовательность жеста, которая примерно параллельна с мультисенсорной последовательностью, описанной в Сенсорных Событиях, Представляют Пальцы на Сенсорной панели, но содержавший в нем. Последовательность жеста начинается, когда драйвер сначала обнаруживает жест и заканчивается, когда драйвер решает, что закончился жест. События типа NSEventTypeBeginGesture
и NSEventTypeEndGesture
отметьте запуск и конечные точки жеста. В большинстве случаев Вы не должны знать о последовательности жеста или этих типах событий; только необходимо реализовать NSResponder
метод для обработки определенного жеста. Однако, если Вы хотите фиксировать изменение, связанное с определенным жестом, таким как регистр работа отмены или выполнить подробное получение, можно реализовать NSResponder
методы beginGestureWithEvent:
и endGestureWithEvent:
в дополнение к методам для определенных жестов.
Если Вы делаете это, однако, необходимо знать о некоторых поведенческих особенностях обнаружения жеста. Во-первых, многократные последовательности жеста могут произойти в единственной мультисенсорной последовательности. Например, пользователь мог бы сначала зажать представление и затем сильно ударить оно, не удаляя все ее пальцы от сенсорной панели. Кроме того, между событиями начинать-жеста и жеста конца последовательности жеста, драйвер сенсорной панели мог бы сначала интерпретировать перемещение как один жест и затем переключить его интерпретацию на другой жест. В настоящее время, однако, это происходит только для, увеличивают и поворачивают жесты. Прокрутите и сильно ударьте, жесты, когда-то начатые, заблокированы к тому жесту, пока не заканчивается жест.
Поскольку это генерирует жесты, аппаратные средства сенсорной панели могли бы также испустить сенсорные события, составляющие жест; система тогда направляет сенсорные события к приложению вместе с событиями жеста. Некоторые сенсорные панели, однако, не поддерживают эту функцию.
Предпочтительная область Сенсорной панели включает опцию для жестов прокрутки: два пальца, перемещающие представление содержания прокрутки, просматривают вокруг. Технически, прокрутите жесты, не определенные жесты, но события от нажатия мыши. Драйвер сенсорной панели переносится, последовательность событий от нажатия мыши, влияющих на представление прокрутки между жестом - начинаются и пара события конца жеста. Кроме обнаружения этих событий, у Вас нет способа определить, было ли событие прокрутки сгенерировано касанием.
Обработка событий жеста
Чтобы обработать событие для определенного жеста — вращение, зажимание, или сильно ударить перемещение — реализуют в Вашем пользовательском представлении надлежащее NSResponder
метод — в этом случае rotateWithEvent:
, magnifyWithEvent:
, или swipeWithEvent:
. В отличие от процедуры для обработки мультисенсорных событий, Ваше пользовательское представление не должно “выбирать - в”. Когда точка мыши по Вашему представлению, и пользователь делает жест, соответствие NSResponder
метод вызывают для обработки события. Если представления ранее в цепочке респондента не обрабатывают событие, это также вызывают.
Каждый из методов обработки жеста имеет NSEvent
параметр. Можно запросить объект-событие для получения информации, подходящей для жеста. Для трех распознанных жестов следующие атрибуты объекта-события имеют особое значение:
Увеличение или (
NSEventTypeMagnify
) —magnification
метод доступа возвращает с плавающей точкой (CGFloat
) значение, представляющее фактор увеличения.Вращение (
NSEventTypeRotate
) —rotation
метод доступа возвращает значение с плавающей точкой, представляющее углы вращения, против часовой стрелки.Сильно ударьте (
NSEventTypeSwipe
) —deltaX
иdeltaY
методы доступа возвращают направление сильно ударения как с плавающей точкой (CGFloat
) значение. НенулевоеdeltaX
значение представляет горизонталь, сильно ударяют;-1 указывает, что сильно-ударять-право и 1 указывает сильно ударение - оставленный. non-0 deltaY представляет вертикаль, сильно ударяют;-1 указывает, что сильно ударение вниз и 1 указывает сильно ударение.
Поворачивание и увеличивает жесты, относительные события. Т.е. каждый rotateWithEvent:
и magnifyWithEvent:
передайте переносы с ним изменение вращения или увеличения начиная с последнего события жеста того типа. Для того, чтобы увеличить масштаб или, Вы добавляете значение от magnification
средство доступа к 1,0 для получения масштабного коэффициента. Для вращения Вы добавляете новейший угол вращения к текущему значению вращения представления. Перечисление 8-2 иллюстрирует, как Вы могли бы сделать это.
Перечисление 8-2 , Обрабатывающее увеличение и жесты вращения
- (void)magnifyWithEvent:(NSEvent *)event { |
[resultsField setStringValue: |
[NSString stringWithFormat:@"Magnification value is %f", [event magnification]]]; |
NSSize newSize; |
newSize.height = self.frame.size.height * ([event magnification] + 1.0); |
newSize.width = self.frame.size.width * ([event magnification] + 1.0); |
[self setFrameSize:newSize]; |
} |
- (void)rotateWithEvent:(NSEvent *)event { |
[resultsField setStringValue: |
[NSString stringWithFormat:@"Rotation in degree is %f", [event rotation]]]; |
[self setFrameCenterRotation:([self frameCenterRotation] + [event rotation])]; |
} |
Обработать сильно ударить жест просто требует, чтобы Вы решили, что направление сильно ударяет путем анализа deltaX
и deltaY
значения. Код в Перечислении 8-3 отвечает на, сильно ударяет путем установки цвета заливки для представления реализации.
Перечисление 8-3 , Обрабатывающее сильно ударить жест
- (void)swipeWithEvent:(NSEvent *)event { |
CGFloat x = [event deltaX]; |
CGFloat y = [event deltaY]; |
if (x != 0) { |
swipeColorValue = (x > 0) ? SwipeLeftGreen : SwipeRightBlue; |
} |
if (y != 0) { |
swipeColorValue = (y > 0) ? SwipeUpRed : SwipeDownYellow; |
} |
NSString *direction; |
switch (swipeColorValue) { |
case SwipeLeftGreen: |
direction = @"left"; |
break; |
case SwipeRightBlue: |
direction = @"right"; |
break; |
case SwipeUpRed: |
direction = @"up"; |
break; |
case SwipeDownYellow: |
default: |
direction = @"down"; |
break; |
} |
[resultsField setStringValue:[NSString stringWithFormat:@"Swipe %@", direction]]; |
[self setNeedsDisplay:YES]; |
} |
Можно также запросить переданный - в NSEvent
объект для другой информации имел отношение к событию жеста, включая расположение указателя мыши в координатах окна (locationInWindow
), метка времени события и любые модифицирующие клавиши, нажатые пользователем.
Поскольку событие жеста получено из мультисенсорной последовательности, могло бы казаться разумным запросить NSEvent
объект для его касаний путем вызова touchesMatchingPhase:inView:
. Однако возвращенный NSTouch
объекты не могли бы быть точным отражением касаний в настоящее время в игре. Таким образом Вы не должны исследовать сенсорные объекты в методах обработки жеста. Единственный надежный набор сенсорных объектов возвращается в методах сенсорной обработки событий такой как touchesBeganWithEvent:
. Для больше на этих методах, посмотрите, что Сенсорные События Представляют Пальцы на Сенсорной панели.
Как упомянуто в Типах Событий Жеста и Последовательностей Жеста, можно также реализовать beginGestureWithEvent:
и endGestureWithEvent:
методы для выполнения действий, таких как объединение всего жеста изменяются между запуском и конечными точками жеста так, чтобы можно было отменить полную последовательность вместо всего одного шага последовательности.
Если Ваше пользовательское представление обрабатывает один из поддерживаемых API жестов (сильно ударьте, увеличьте и вращайтесь), реализацию Вашего представления вызывают вместо любой другой реализации, если Ваше представление перед другим объектом в цепочке респондента. Однако существуют определенные жесты в масштабе всей системы, такой, поскольку сильно ударяет с четырьмя пальцами. для которого внедрение систем имеет приоритет по любому жесту, обрабатывающему приложение, выполняет.
Сенсорные события представляют пальцы на сенсорной панели
Вместо того, чтобы обработать жест, Вы могли принять решение отследить и обработать «необработанные» касания, составляющие жест. Но почему Вы могли бы сделать такой выбор? Одна очевидная причина состоит в том, что OS X не распознает определенный жест, Вы интересуетесь — т.е. что-то другое, чем увеличивают (повышение в и), вращаются или сильно ударяют. Или Вы хотите, чтобы Ваше представление реагировало на поддерживаемый системой жест, но Вы хотите больше информации о жесте, чем в настоящее время обеспечивает платформа AppKit; например, требуется иметь точки привязки для работы изменения масштаба. Если у Вас нет причин, таких как они, необходимо предпочесть жесты необработанным сенсорным событиям.
Следующие разделы обсуждают мультисенсорную последовательность, разграничивающую сенсорное событие в абстрактном смысле, укажите на важные атрибуты сенсорного события и покажите Вам, как обработать сенсорные события.
Мультисенсорная последовательность
Когда пользователь касается сенсорной панели с одним или более пальцами и шевелит теми пальцами по сенсорной панели, аппаратные средства генерируют низкоуровневые события, представляющие каждый из тех пальцев на сенсорной панели. Поток событий, как со всем типом событий, непрерывен. Однако существует логическая единица касаний, что вместе, представляйте мультисенсорную последовательность. Когда пользователь помещает один или несколько пальцев на сенсорную панель, мультисенсорная последовательность начинается. Палец может переместиться в различные направления по сенсорной панели, и дополнительные пальцы могут коснуться сенсорной панели. Мультисенсорная последовательность не заканчивается, пока всеми теми пальцами не шевелят от сенсорной панели.
В мультисенсорной последовательности палец на сенсорной панели обычно проходит через отличные фазы:
Это приземляется на сенсорной панели.
Это может переместиться в различные направления на различных скоростях.
Это может остаться стационарным.
Это поднимается с сенсорной панели.
Платформа AppKit использует объекты NSTouch
класс для представления касаний через различные фазы мультисенсорной последовательности. Т.е. NSTouch
объект является снимком определенного пальца — касания — на сенсорной панели в определенной фазе. Например, когда касание перемещается в определенное направление, AppKit представляет его с NSTouch
экземпляр; это использует другого NSTouch
объект представлять тот же палец, когда это поднимается с сенсорной панели.
Каждый сенсорный объект содержит свою фазу как свойство, значение которого является одним из NSTouchPhase
константы, показанные в Перечислении 8-4. Это также имеет identity
свойство, которое Вы используете для дорожки NSTouch
экземпляр через мультисенсорную последовательность. (Сенсорные Идентификационные данные и Другие Атрибуты описывают сенсорные идентификационные данные более подробно.) Рисунок 8-2 иллюстрирует мультисенсорную последовательность и роль этих свойств в этой последовательности.
AppKit присоединяет касания в мультисенсорной последовательности к представлению, находящемуся под указателем мыши, когда первый палец в последовательности приземляется на сенсорной панели. Касание остается присоединенным к этому представлению, пока это не закончилось (т.е. лифты пальца) или пока не отменяется мультисенсорная последовательность. Любые интерпретации касаний в мультисенсорной последовательности должны относиться к тому представлению и тому представлению только. У Вас не может быть касаний, связанных с различными взглядами в той же мультисенсорной последовательности. Касание, как представлено a NSTouch
возразите, не имейте соответствующего расположения на экране или расположения в его представлении. Но можно определить его изменяющиеся позиции на сенсорной панели, и из той карты значение дельты для преобразования представления.
Константы перечисления 8-4 для сенсорных фаз
enum { |
NSTouchPhaseBegan = 1U << 0, |
NSTouchPhaseMoved = 1U << 1, |
NSTouchPhaseStationary = 1U << 2, |
NSTouchPhaseEnded = 1U << 3, |
NSTouchPhaseCancelled = 1U << 4, |
NSTouchPhaseTouching = NSTouchPhaseBegan | NSTouchPhaseMoved | NSTouchPhaseStationary, |
NSTouchPhaseAny = NSUIntegerMax |
}; |
typedef NSUInteger NSTouchPhase; |
Сенсорные идентификационные данные и другие атрибуты
NSTouch
определяет много свойств для его экземпляров. Особенно важное свойство identity
. Как можно вспомнить из предыдущего обсуждения, приложение создает NSTouch
объект представлять тот же палец на сенсорной панели для каждой фазы это проходит через в мультисенсорной последовательности. Несмотря на то, что это различные объекты, у них есть то же identity
возразите значению, позволив Вам отследить изменения в касании всюду по мультисенсорной последовательности. Можно определить, относятся ли два сенсорных объекта к определенному пальцу на сенсорной панели путем сравнения их с isEqual:
метод:
if ([previousTouchObject.identity isEqual:currentTouchObject.identity]) { |
// object refers to same finger on trackpad...do something appropriate |
} |
И сенсорные идентификационные данные возражают и NSTouch
сами объекты принимают NSCopying
протокол. Можно поэтому скопировать их. Эта возможность означает, что можно использовать объекты сенсорных идентификационных данных в качестве ключей NSDictionary
наборы.
Два других важных и связанных свойства NSTouch
объекты normalizedPosition
и deviceSize
. Касание не имеет никакого видимого расположения на экране. (Курсор мыши только идентифицирует представление, сначала получающее сенсорные события, если он реализует требуемые методы.) Касание действительно, однако, имеет позицию на сенсорной панели. Сенсорной панели определил систему координат источник (0,0) в нижнем левом углу сенсорной панели и высоты и ширины, определенной deviceSize
. Его позиция в этой системе координат возвращается normalizedPosition
. Используя эти два свойства можно получить значения дельты для сенсорных перемещений и применить их к трансформациям представления, которым управляют. Это проиллюстрировано в примере кода в Перечислении 8-7.
Отдых касаний
Драйвер сенсорной панели мог бы идентифицировать один или несколько пальцев (и ползунок) как отдых. Это состояние «отдыха» означает, что палец или ползунок находятся физически на цифровом преобразователе, но драйвер решает, что это не должно использоваться для ввода. Например, с buttonless сенсорными панелями, пользователь может положить его или ее ползунок на нижний раздел сенсорной панели, как каждый кладет их руки на отдых руки. Эта цифра проигнорирована, как введено, и ее перемещение не перемещает указатель мыши.
Драйвер мог бы также перейти касание в или из покоящегося состояния в любое время, на основе его оценки. Перемещение покоящегося пальца или ползунка является не всегда детерминантом. Покоящийся палец, который перемещения не могли бы обязательно перейти из «отдыха». С другой стороны, покоящийся палец или ползунок не должны физически перемещаться вообще для перехода в и из «отдыха».
Даже если касание отмечается как «покоящийся», чтобы обозначить, что должен быть проигнорирован, драйвер все еще генерирует сенсорные данные для него и отправляет событие в приложение для каждой сенсорной фазы. По умолчанию эти события не поставлены представлениям и не включены в набор события касаний. Однако можно включить эту возможность путем вызова NSView
метод setWantsRestingTouches:
с параметром YES
. Если Вы не принимаете покоящиеся касания, знают это NSTouchPhaseBegan
и NSTouchPhaseEnded
события сгенерированы когда сенсорные переходы от или до покоящегося состояния.
Обработка мультисенсорных событий
Представление по умолчанию не принимает сенсорные события. Для обработки сенсорных событий пользовательское представление должно сначала вызвать NSView
метод setAcceptsTouchEvents:
с параметром YES
. Тогда Ваше представление должно реализовать NSResponder
методы для сенсорной обработки событий:
- (void)touchesBeganWithEvent:(NSEvent *)event; |
- (void)touchesMovedWithEvent:(NSEvent *)event; |
- (void)touchesEndedWithEvent:(NSEvent *)event; |
- (void)touchesCancelledWithEvent:(NSEvent *)event; |
Для пользовательского подкласса NSView
, необходимо реализовать каждый из этих методов. Если Вы разделяете на подклассы класс, обрабатывающий касания, Вы не должны реализовывать все эти методы методов, но необходимо вызвать реализацию суперкласса в методах, которые Вы действительно переопределяете.
Приложение вызывает каждый из этих методов на представлении, когда касание вводит фазу — т.е. когда палец приземляется, когда это углубляет сенсорную панель, когда это поднимается с сенсорной панели, и когда операционная система отменяет мультисенсорную последовательность по некоторым причинам. Больше чем один из этих после методов можно было вызвать для того же события. Приложение сначала отправляет эти сообщения в представление, находящееся под указателем мыши. Если то представление не обрабатывает событие, от события отказываются цепочка респондента.
Единственный параметр этих методов респондента NSEvent
объект. Можно получить набор NSTouch
объекты имели отношение к данной фазе путем отправки a touchesMatchingPhase:inView:
к объекту-событию, передающему в константе для фазы. Например, в touchesBeganWithEvent:
метод можно получить сенсорные объекты, представляющие пальцы, только что приземлившиеся с вызовом, подобным этому:
NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:self]; |
Вызовы операционной системы touchesCancelledWithEvent:
когда внешнее событие — например, деактивация приложения — прерывает текущую мультисенсорную последовательность. Необходимо реализовать touchesCancelledWithEvent:
метод к бесплатным ресурсам, выделенным для сенсорной обработки или сбрасывать переходное состояние, привыкшее в сенсорной обработке к начальным значениям.
Остающиеся примеры кода взяты из проекта примера кода LightTable. Во-первых, проект объявляет, что два статических массива содержат начальные касания и текущие касания:
NSTouch *_initialTouches[2]; |
NSTouch *_currentTouches[2]; |
Перечисление 8-5 иллюстрирует реализацию touchesBeganWithEvent:
метод. В этом методе представление получает все касания, связанные с событием и, если существует два касания, хранилища их в двух статических массивах.
Перечисление 8-5 , Обрабатывающее касания в touchesBeganWithEvent:
- (void)touchesBeganWithEvent:(NSEvent *)event { |
if (!self.isEnabled) return; |
NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self.view]; |
if (touches.count == 2) { |
self.initialPoint = [self.view convertPointFromBase:[event locationInWindow]]; |
NSArray *array = [touches allObjects]; |
_initialTouches[0] = [[array objectAtIndex:0] retain]; |
_initialTouches[1] = [[array objectAtIndex:1] retain]; |
_currentTouches[0] = [_initialTouches[0] retain]; |
_currentTouches[1] = [_initialTouches[1] retain]; |
} else if (touches.count > 2) { |
// More than 2 touches. Only track 2. |
if (self.isTracking) { |
[self cancelTracking]; |
} else { |
[self releaseTouches]; |
} |
} |
} |
Когда один или оба из перемещения пальцев, touchesMovedWithEvent:
метод вызывается. Представление в LightTable
реализации этот метод как показано в Перечислении 8-6. Снова, это получает все сенсорные объекты, связанные с событием и, если существует точно два касания, это соответствует текущие касания их начальным дубликатам. Тогда это вычисляет значения дельты для источника и размера и, если они превышают определенный порог, вызывает метод действия выполнить трансформацию.
Перечисление 8-6 , Обрабатывающее касания в touchesMovedWithEvent:
- (void)touchesMovedWithEvent:(NSEvent *)event { |
if (!self.isEnabled) return; |
self.modifiers = [event modifierFlags]; |
NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self.view]; |
if (touches.count == 2 && _initialTouches[0]) { |
NSArray *array = [touches allObjects]; |
[_currentTouches[0] release]; |
[_currentTouches[1] release]; |
NSTouch *touch; |
touch = [array objectAtIndex:0]; |
if ([touch.identity isEqual:_initialTouches[0].identity]) { |
_currentTouches[0] = [touch retain]; |
} else { |
_currentTouches[1] = [touch retain]; |
} |
touch = [array objectAtIndex:1]; |
if ([touch.identity isEqual:_initialTouches[0].identity]) { |
_currentTouches[0] = [touch retain]; |
} else { |
_currentTouches[1] = [touch retain]; |
} |
if (!self.isTracking) { |
NSPoint deltaOrigin = self.deltaOrigin; |
NSSize deltaSize = self.deltaSize; |
if (fabs(deltaOrigin.x) > _threshold || |
fabs(deltaOrigin.y) > _threshold || |
fabs(deltaSize.width) > _threshold || |
fabs(deltaSize.height) > _threshold) { |
self.isTracking = YES; |
if (self.beginTrackingAction) |
[NSApp sendAction:self.beginTrackingAction to:self.view from:self]; |
} |
} else { |
if (self.updateTrackingAction) |
[NSApp sendAction:self.updateTrackingAction to:self.view from:self]; |
} |
} |
} |
Перечисление 8-7 показывает, как проект вычисляет значения дельты для преобразования источника представления. Отметьте, как код использует значения от NSTouch
свойства normalizedPosition
и deviceSize
в этом вычислении.
Перечисление 8-7 Получая использование значения дельты normalizedPosition
и deviceSize
- (NSPoint)deltaOrigin { |
if (!(_initialTouches[0] && _initialTouches[1] && |
_currentTouches[0] && _currentTouches[1])) return NSZeroPoint; |
CGFloat x1 = MIN(_initialTouches[0].normalizedPosition.x, _initialTouches[1].normalizedPosition.x); |
CGFloat x2 = MAX(_currentTouches[0].normalizedPosition.x, _currentTouches[1].normalizedPosition.x); |
CGFloat y1 = MIN(_initialTouches[0].normalizedPosition.y, _initialTouches[1].normalizedPosition.y); |
CGFloat y2 = MAX(_currentTouches[0].normalizedPosition.y, _currentTouches[1].normalizedPosition.y); |
NSSize deviceSize = _initialTouches[0].deviceSize; |
NSPoint delta; |
delta.x = (x2 - x1) * deviceSize.width; |
delta.y = (y2 - y1) * deviceSize.height; |
return delta; |
} |
Наконец, представление реализует touchesEndedWithEvent:
и touchesCancelledWithEvent:
методы, как показано в Перечислении 8-8, прежде всего для отмены отслеживания события.
Окончание Обработки перечисления 8-8 и отмененные касания
- (void)touchesEndedWithEvent:(NSEvent *)event { |
if (!self.isEnabled) return; |
self.modifiers = [event modifierFlags]; |
[self cancelTracking]; |
} |
- (void)touchesCancelledWithEvent:(NSEvent *)event { |
[self cancelTracking]; |
} |
Параграф
События от нажатия мыши и сенсорная панель
Операционная система интерпретирует единственный палец, преодолевающий сенсорную панель как отслеживающее мышь событие, и перемещает указатель мыши в соответствующую скорость и направление. Перемещение единственного пальца генерирует и события жеста и события от нажатия мыши, несмотря на то, что события жеста проигнорированы, если представление не принимает касания. Перемещения больше чем одного пальца на сенсорной панели не перемещают курсор, несмотря на то, что они могут все еще привести к генерации событий от нажатия мыши, используемых в прокрутке. Исключение к этому является buttonless сенсорной панелью, где два пальца могут быть физически касающимися сенсорная панель, в то время как курсор перемещается, потому что покоится один из них.
Если событие от нажатия мыши сгенерировано сенсорным событием, подтип события от нажатия мыши NSTouchEventSubtype
. Вы могли оценить объекты события от нажатия мыши определить, когда проигнорировать события от нажатия мыши в пользу сенсорных событий, когда они оба сгенерированы. (Это уведомление не применимо к событиям колесика прокрутки.)
Вы не должны пытаться извлечь касания из события от нажатия мыши с помощью touchesMatchingPhase:inView:
метод. Несмотря на то, что можно проверить подтип объекта-события, чтобы видеть, генерировало ли касание событие от нажатия мыши, Вы не можете коррелировать событие от нажатия мыши ни к какому определенному касанию. Далее, Вы не можете запросить сенсорное событие, чтобы узнать, генерировало ли оно также событие от нажатия мыши.