UIGestureRecognizer:теория,практика,кастомизация
ПредставляяпервыйiPhone于2007年年初发行,СтивДжобсапеллировалкустареваниюконцепциифизическойклавиатуру Сэтогомоментанаразвитиеустройствскачественнымитачскринами,позоои Теперьпалец – главныйинструментуправлениядевайсомимыможемтапатьпокнопкам,свайпатьсписки,пинчитьфотографии…Давайтеразберемсякакэтореализованососторонысофтаинаучимсяиспользоватьвсюмощьмеханизмараспознаванияжестов。
UITouchиегообработка
Нодавайтепопорядку。 Передтем,какначинатьраспознаватьжесты,надопонять,каквообщеприложениеполучаетинформациюокасаниях,свайпах,нажатияхнаэкраниктоихобрабатывает。
Чтопроисходит,когдапалецпользователякасаетсяэкрана? Системасоздаетобъекттипаевоетере Этозначит,чтонавремявсейцепочкисобытий
“палецкоснулсяэкрана→палецдвижетсяпоэкрану→палецоторвалсяотэкрана”
длякаждогопальца,касающегосяэкрана,существуетуникальныйобъектUITouch。 Далее,используямеханизм命中测试’,находитсясамаяглубокаявиирархииUIView,框架которойсодержиевсеб ПолученнаяUIViewстановитсяfirstResponder ,使用UITouchипрокидыватьихдальшепоresponseerChain 。
Дляобработкипоступающихсобытий,UIViewпредоставляетнесколькометодов:
- touchesBegan(_ touches:设置,并带有事件:UIEvent?) —началокасания(экранакоснулисьпальцы)
- touchesMoved(_ touches:Set ,事件:UIEvent?) —изменениепараметровкасания(позициянаэкране,сила(ForceTouch))
- touchesEnded(_ touches:设置,带有事件:UIEvent?) —конецкасания(пальцыбылиубранысэкрана)
- touchesCancelled(_ touches:Set ,事件:UIEvent?) —отменакасания(далеерассмотрим,чтоэтозначит)
ТаккакэкранiPhoneподдерживаетмультитач,товодинмоментвремениможетизменитьсясостояниесразу Например,еслипользователькоснетсяэкранадвумяпальцамиодновременно,системавызоветtouchesBegan лишьодинраз,новомножестве 设置 мыполучимдваобъекта—图库矢量图片。
Первыетриметода( 的touchesBegan,touchesMoved,touchesEnded)отвечаютза“нормальный”жизненныйциклUITouchивызываютсяприначалекасания,измененииегопараметров(позициянаэкране,силанажатия)иконцекасаниясоответсвенно。
Однако, 触摸 выбиваетсяизихряда已取消。 Насамомделе,концомжизненногоциклаUITouchможетбытьнетолькофизическийконецжеста,ноикакое-либопрограммноесобытие,вследствиекоторогосистемабудетвынужденапрерватьобработку данногокасания 。 Этоможетпроизойти,например,вслучае,еслипоявилсяинтерфейсвходящегозвонкаипродолжениеобработкикасаниябудетнекорректным – пользовательуженаходитсявконтекстедругогоприложения(телефон)。 Ожидается,чтоприполученииtouches已取消 приложениеотменитвседействиякоторыемоглибытьпротевреивведен。 Дляпониманиялогикиэтоготребованиярассмотримкнопку。 Пустьпользовательнажалнанее,ноещенеподнялпалецивэтовремяпроисходитвходящийзвонок。 ЕслиобработатьtouchesCancelledаналогичноtouchesEndedивызватьобработчикнажатиякнопки,топослеокончаниязвонкаивозвратавприложение будетпроизведенокакое -тодействие,котороепользовательмогнеожидать。
Знаякакобрабатыватьтач-события,мы,вообщеговоря,можемреализоватьскольугодносложнуюлогикуиначатьвычленятьизнихнечто,чтоможетнасинтересовать。 Давайте,например,попробуемобрабатыватьдолгоенажатиенаUIView。
UIGestureRecognizer和UIView
Главноечеопомнить— UIGestureRecognizerпервымполучаетправообработкиUITouchивентов 。 UIGestureRecognizer ‘响应者链’ыстоятнемноговсторонеотобычногомеханизма’。 Система,определивчерезUITestвкоторуюпопалпалецпользователя,собиреевере Средисобранныхрекогнайзеровопределяетсямножествотех,которыебудуработатьипорядокихработы(этоповедениезадаетсячерезделегатарекогнайзераимырассмотримегочутьдалее)。 UIGestureRecognizer可以将UITouch转换为UITouch ,然后将UIView更改为узнает。 Болеетого,еслирекогнайзерперехватитUITouch,тоеноувидитвообщениоднаUIViewвreserChainвоеон
УвидитлиUIViewэтисобытиязависитотреализациирекогнайзераи/илиегонастроек。 Опустивзависимостьотконкретнойреализации,рассмотримкакиепараметрывлияютнадоставкасобыти
- cancelsTouchesInView:Bool (默认值:true)
- delaysTouchesBegan:Bool (默认值:false)
- delaysTouchesEnded:布尔型(默认值:true)
Разберемпо-порядку。
cancelsTouchesInView — UIView , UITouch ,которыеужебылипереданыкэтомумоментувUIView, но имеющиеотношениекжесту,будутотменены( touchesCancelled )。 UITouch的 UIView界面上的图标,可能是UIView的外观,也可能是UIView的外观。
Дляпониманиярассмотримпример:ThreeFingerRecognizer,детектирующийкасаниетремяпальцами。 Переопределимметодыtouches {XXX},在 UIView上,在 добавиввнихprintипосмотримкакбудетменятьсявыводвзависимост上。
- Максимальноечислокасанийвжесте— 1(перетаскиваемоднимпальцем)。
- Сохраняемточкуначалажеста。
- ПрикаждомсдвигепальцаобновляемпозициюUIViewнаэкраненатребуемуювеличину。
Дальшепоспискузум— UIUI的иипковымжестомдвумяпальцамиизменятьразмер UIPinchGestureRecognizer 。 Общаяидеяаналогичнаподходусперетаскиванием。
Запустивприложениеможнозаметить,чтовповеденииестьизъян。 Чтобудет,еслиначатьдвигатьквадратоднимпальцем,апотом,коснувшисьэкранавторым,попытат UIPinchGestureRecognizer会在UIView界面上显示неменяется。 Инаоборот,еслиначатьзумитьквадратдвумяпальцами,тосистемауженедастегосдвинутьсместа。 Настаетвремяделегата!
Остаетсяразобратьсясповоротом。 Есливыдочиталидоэтойточки,тоувасужедостаточнознаний,чтобыреализоватьэтуфункциоельно。 Нуаеслинавашемпутивстретятсяпроблемы,товывсевлакполномукодупример。
Добавимещеоднотребованиекнашемуприложению。 ПустьпотапунаUIViewбудетменятьсяеёцвет,以及подвойномутапувозвращатьсякначальнымзначеира。 ДляобработкитаповбудемиспользоватьдваUITapGestureRecognizer’аинезабудемнастроитьпорядорееоее
- Ключевоймоментпримера—解决方案
Ноневсегдаобязательнописатьтакмногокодадляработысделегатами。 Есливоднойточкеимеетсядоступкобоим рекогнайзерам ,тореализоватьсхожееповедениеможночерезявноеопределение зависимостипосредствамметода 需要(toFail otherGestureRecognizer:UIGestureRecognizer)。
КастомныйUIGestureRecognizer
UIKitпредоставляемнамбогатыйнаборрекогнайзероввсехосновных“ iOSжестов”, Ночто,еслипоставленнаязадачавсежевыходитзарамкивозможностейстандартныхрекогнайзеров? Безусловноможнонаписатьсвоюреализацию!
Первымшагомреализациисобственногорекогнайзерадолжнобытьдобавление строчки 进口UIKit.UIGestureRecognizerSubclass,чтоподключиткатегориюклассаUIGestureRecognizerспереопределениемсвойства 状态 исделаетегодоступнымназапись。
Реализациясвоегорекогнайзерасводитсякпереопределениюужезнакомых намметодов 的touchesBegan /移动/端/取消 вкоторыхдолжнабытьсосредоточенавсялогикапо обработкесобытийивычлененияизнихтребуемыхжестов 。 Такженеобходимопереопределитьметодreset ()或которомнеобходимоочищатьсостояниерекогнайзера。 И,последнее,чтоможетнампригодится – метод 忽略(_触控:UITouch,事件:的UIEvent),посредствамкоторого,мыможемсообщитьсистеме,чтоконкретныйUITouchнеотноситсякнашемужестуимыне хотимдалееполучатьуведомленияоегоизменениях 。
Собираявсевоедино,давайтенапишемсвойнепрерывныйрекогнайзер,которыйбудетраспознаватьсильноенажатие(ForceTouch)и,еслисилапревысилазаданныйпорог,тоуведомлять目标оеёизменении。
Каквидите,кодсильнопт,чтомыписаливпримерепрораспознаваниедолгогонажатиянаUIView。 Нонадонезабыватьпрокорректнуюреализациюметодаreset () 。
Вместозаключения
ИзэтойстатьивымоглиполучитьосновныезнаниядляработысUIGestureRecognizer’амииреализациисвоихсобств。
ПолныйкодпримеровможнонайтинаGitHub。
Крометогоникогданебываетлишнимпочитатьофициальнуюдокументацию:
- UIGestureRecognizer
- 手势识别器状态机
- 实施自定义识别器