Изменение масштаба путем ответвления
В то время как основное UIScrollView
класс поддерживает повышение - в и жесты повышения с очень мелкой суммой кода, поддерживание более богатого опыта изменения масштаба с помощью обнаружения касания требует большего количества работы со стороны приложения.
Инструкции по Интерфейсу пользователя iOS определяют двойное касание, чтобы увеличить масштаб и уменьшить масштаб. Это, однако, принимает некоторые определенные ограничения: то, что представление имеет единственный уровень изменения масштаба, такой как в фото приложении, или что последовательные двойные касания будут масштабировать к максимальной сумме и, когда-то достиг следующих изменений масштаба двойного касания назад к полноэкранному представлению. Но некоторые приложения требуют более гибкого поведения при контакте с функциональностью касания к изменению масштаба, примером этого является приложение Карт. Карты поддерживают двойное касание для увеличивания масштаб с дополнительными двойными касаниями, увеличивающими масштаб далее. Для уменьшения масштаб в последовательных суммах Карты используют касание с двумя пальцами, с пальцами близко друг к другу, для уменьшения масштаб шаг за шагом. В то время как этот жест не определяется в Инструкциях по Интерфейсу пользователя iOS, приложения могут принять решение принять его для имитации приложения Карт, когда требуется функциональность.
Для Вашего приложения для поддержки касания для изменения масштаба функциональности Вы не должны разделять на подклассы UIScrollView
класс. Вместо этого Вы реализуете требуемую сенсорную обработку в классе для который UIScrollView
метод делегата viewForZoomingInScrollView:
возвраты. Тот класс будет ответственен за отслеживание числа пальцев на экране и количестве касания. Когда это обнаружит единственное касание, двойное касание или касание с двумя пальцами, это ответит соответственно. В случае двойного касания и касания с двумя пальцами, это должно программно масштабировать представление прокрутки надлежащим фактором.
Реализация обрабатывающего касание кода
При поддержке касания, удваивают касание и касание с двумя пальцами в сенсорном коде подкласса UIView
(или потомок), требует реализации трех методов: touchesBegan:withEvent:
, touchesEnded:withEvent:
, и touchesCanceled:withEvent:
. Кроме того, инициализация взаимодействия, многократных касаний и переменных отслеживания может требоваться. Следующие фрагменты кода от примера TapToZoom в проекте примера кода ScrollViewSuite, в TapDetectingImageView
класс, который является подклассом UIImageView
.
Инициализация
Жесты, которые желаемы для реализации касания к изменению масштаба, требуют, чтобы взаимодействие с пользователем и многократные касания были включены для представления, и методы для добавления той функциональности вызывают от initWithImage:
метод. Этот метод также инициализирует две переменные экземпляра, использующиеся для отслеживания состояния в сенсорных методах. twoFingerTapIsPossible
свойство является булевской переменной, которая является YES
если больше чем два пальца не находятся в контакте с экраном устройства. multipleTouches
свойство имеет значение NO
если их не больше чем одно сенсорное обнаруженное событие. Третье свойство, tapLocation
, CGPoint, использующийся для отслеживания расположения двойного касания или средней точки между двумя пальцами, когда обнаруживается двойное касание. Эта точка тогда используется в качестве центральной точки для того, чтобы увеличить масштаб или использовать программируемые методы изменения масштаба, описанные в Изменении масштаба Программно.
- (id)initWithImage:(UIImage *)image { |
self = [super initWithImage:image]; |
if (self) { |
[self setUserInteractionEnabled:YES]; |
[self setMultipleTouchEnabled:YES]; |
twoFingerTapIsPossible = YES; |
multipleTouches = NO; |
} |
return self; |
} |
Как только инициализация произошла, класс готов, когда это получает сенсорные события.
touchesBegan:withEvent: Реализация
touchesBegan:withEvent:
метод сначала отменяет любые выдающиеся попытки инициировать обработку единственного касания пальца, handleSingleTap
сообщение. Сообщение отменяется, потому что, если оно было отправлено, это недопустимо, поскольку это - дополнительное сенсорное событие, исключая единственное касание. Если сообщение не было отправлено, потому что это - первое касание, отменение выполнения, проигнорирован.
Метод тогда обновляет состояние переменных отслеживания. Если больше, чем единственное сенсорное событие были получены, то multipleTouches
свойство установлено в YES
, потому что это может быть двумя касаниями пальца. Если больше чем два сенсорных события имели место, то twoFingerTapIsPossible
свойство установлено в NO
, касания больше чем двумя пальцами за один раз являются проигнорированным жестом.
Код для этого метода следующие:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event |
{ |
// Cancel any pending handleSingleTap messages. |
[NSObject cancelPreviousPerformRequestsWithTarget:self |
selector:@selector(handleSingleTap) |
object:nil]; |
// Update the touch state. |
if ([[event touchesForView:self] count] > 1) |
multipleTouches = YES; |
if ([[event touchesForView:self] count] > 2) |
twoFingerTapIsPossible = NO; |
} |
touchesEnded:withEvent: Реализация
Этот метод является рабочей лошадью обработки касания и несколько сложен. Однако код хорошо документируется и просто показан ниже. midPointBetweenPoints
функция используется для определения точки, которая двойное касание будет центрироваться на когда handleTwoFingerTap
метод вызывают, который приводит к представлению, уменьшающему уровень.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event |
{ |
BOOL allTouchesEnded = ([touches count] == [[event touchesForView:self] count]); |
// first check for plain single/double tap, which is only possible if we haven't seen multiple touches |
if (!multipleTouches) { |
UITouch *touch = [touches anyObject]; |
tapLocation = [touch locationInView:self]; |
if ([touch tapCount] == 1) { |
[self performSelector:@selector(handleSingleTap) |
withObject:nil |
afterDelay:DOUBLE_TAP_DELAY]; |
} else if([touch tapCount] == 2) { |
[self handleDoubleTap]; |
} |
} |
// Check for a 2-finger tap if there have been multiple touches |
// and haven't that situation has not been ruled out |
else if (multipleTouches && twoFingerTapIsPossible) { |
// case 1: this is the end of both touches at once |
if ([touches count] == 2 && allTouchesEnded) { |
int i = 0; |
int tapCounts[2]; |
CGPoint tapLocations[2]; |
for (UITouch *touch in touches) { |
tapCounts[i] = [touch tapCount]; |
tapLocations[i] = [touch locationInView:self]; |
i++; |
} |
if (tapCounts[0] == 1 && tapCounts[1] == 1) { |
// it's a two-finger tap if they're both single taps |
tapLocation = midpointBetweenPoints(tapLocations[0], |
tapLocations[1]); |
[self handleTwoFingerTap]; |
} |
} |
// Case 2: this is the end of one touch, and the other hasn't ended yet |
else if ([touches count] == 1 && !allTouchesEnded) { |
UITouch *touch = [touches anyObject]; |
if ([touch tapCount] == 1) { |
// If touch is a single tap, store its location |
// so it can be averaged with the second touch location |
tapLocation = [touch locationInView:self]; |
} else { |
twoFingerTapIsPossible = NO; |
} |
} |
// Case 3: this is the end of the second of the two touches |
else if ([touches count] == 1 && allTouchesEnded) { |
UITouch *touch = [touches anyObject]; |
if ([touch tapCount] == 1) { |
// if the last touch up is a single tap, this was a 2-finger tap |
tapLocation = midpointBetweenPoints(tapLocation, |
[touch locationInView:self]); |
[self handleTwoFingerTap]; |
} |
} |
} |
// if all touches are up, reset touch monitoring state |
if (allTouchesEnded) { |
twoFingerTapIsPossible = YES; |
multipleTouches = NO; |
} |
} |
touchesCancelled:withEvent: Реализация
Представление получает a touchesCancelled:withEvent:
обменивайтесь сообщениями, если представление прокрутки обнаруживает, что обработка касания больше не релевантна, потому что палец переместился, который вызывает прокрутку к тому, чтобы быть. Этот метод просто сбрасывает переменные состояния.
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { |
twoFingerTapIsPossible = YES; |
multipleTouches = NO; |
} |
Пример комплекта ScrollView
Проект примера кода ScrollViewSuite имеет превосходные примеры реализации изменения масштаба с помощью жестов касания. TapToZoom
пример в комплекте реализует подкласс UIImageView
это поддерживает изменение масштаба с помощью касающегося поведения, как выведено на экран в приложении Карт. Реализация достаточно универсальна, через это - использование делегата (обычно контроллер, управляющий представлением прокрутки) реализовать фактическую обработку касания, двойного касания, или дважды затроньте, что необходимо быть в состоянии легко адаптировать код и проект, к собственным представлениям.
TapDetectingImageView
класс является подклассом UIImageView
это реализует сенсорную обработку, с помощью RootViewController
класс как делегат, обрабатывающий фактическое касание и сенсорные ответы, а также контроллер, первоначально конфигурирующий UIScrollView
.