Obsah
20 tipů, jak zrychlit klávesnici na iOS
Práce s klávesnicí v iOS: jak minimalizovat copy-paste
Při vývoji téměř jakékoli mobilní aplikace se vývojář bude muset vypořádat se vstupními poli. A tam, kde jsou vstupní pole, je klávesnice a také logika spojená se zpracováním událostí jejího životního cyklu: zobrazení, skrytí, změna velikosti.
Každý, kdo vyvíjel aplikaci pro iOS, ví, že práce s klávesnicí je součástí velmi podobného nebo dokonce identického kódu, jehož název je copy-paste. Jak jsme se s tím u Surfu poprali a jak moc se nám podařilo zredukovat kódovou základnu, si povíme v článku.
Řekněme, že máme obrazovku se vstupním polem. Když klepnete, zobrazí se klávesnice. Naším cílem je zvládnout vzhled a následné zmizení klávesnice z obrazovky v závislosti na její velikosti a době objevení nebo skrytí. Kód může vypadat takto:
// метод, в котором происходит подписка на события от NotificationCenter func subscribeOnKeyboardNotifications() < let center = NotificationCenter.default center.addObserver(self, selector: #selector(keyboardWillBeShown(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) center.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) >// метод, вызываемый при появлении клавиатуры @objc func keyboardWillBeShown(notification: Notification) < // пытаемся получить доступ к высоте клавиатуры и времени анимации guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, let animationTime = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else < return >let keyboardHeight = keyboardFrame.height // выполняем код > // метод, вызываемый при сокрытии клавиатуры @objc func keyboardWillBeHidden(notification: Notification) < // пытаемся получить доступ к высоте клавиатуры guard let animationTime = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else < return >// выполняем код >
Předpokládejme, že se objeví druhá obrazovka se vstupními poli. Žádný problém: zkopírujeme dříve napsané metody a změníme pouze zpracování událostí.
A pak se objeví třetí obrazovka, čtvrtá. Myslím, že už chápete, na co narážím: na všech obrazovkách se objeví naprosto stejný kód, liší se pouze zpracováním událostí. Je vysoká pravděpodobnost, že vývojář nenapíše kód od začátku, ale zopakuje jej pomocí Cmd+C/Cmd+V.
To nám jasně naznačuje, že je čas přemýšlet o opětovném použití kódu, abyste se vyhnuli kopírování a vkládání. Takže vznikl nápad napsat nástroj, který by:
- Umožnil vám přihlásit se k odběru nebo odhlásit odběr událostí klávesnice.
- Volá se předdefinovaná metoda na události vzhledu a skrytí klávesnice.
- Zároveň tam nepřenesl surový objekt Notification, ale data požadovaného typu: animationDuration, keyboardFrame a tak dále.
- Osvobodilo mě to od práce s NotificationCenter, což mi umožnilo pokaždé si bolestně pamatovat potřebné klíče a datové typy.
- Osvobodilo mě to od potřeby kopírovat a vkládat kód.
Jak jsme vytvořili utilitu
První problém na cestě k čistému kódu: jak uspořádat myšlenku z architektonického hlediska? Chceme přesunout zpracování událostí klávesnice mimo ViewController, ale budeme muset volat jeho metody. Vyvstávají otázky:
- Kde vyřizovat akce?
- Jak mohu přiřadit objekt k ViewControlleru, kde bude probíhat toto zpracování?
- Jak mohu zajistit, aby byl někde uložen silný odkaz na takový objekt?
Základní třídy nejsou naším přístupem. Chtěl bych, aby byl systém flexibilní: základní třídy k tomu nepřispějí.
Níže uvedený diagram a krátký seznam vám pomohou pochopit první verzi nástroje:
veřejný protokol KlávesnicePozorovatelné: třída
Princip fungování je následující:
- Označujeme, že ViewController vyhovuje protokolu KeyboardObservable.
- Protokol obsahuje 4 metody. Dvě z nich – přihlášení a odhlášení – jsou implementovány ve výchozím rozšíření tohoto protokolu, takže je není potřeba implementovat.
- Během procesu odběru oznámení se vytvoří objekt pozorovatele, který obsahuje slabý odkaz na ViewController. Bude zodpovědná za zpracování událostí vzhledu a skrytí klávesnice: jsou to její metody, které budou volány při spuštění oznámení.
- Pokud se klávesnice objeví nebo zmizí, pozorovatel vyvolá dvě odpovídající metody.
To řeší část problému: nyní není potřeba implementovat metody pro přihlášení a odhlášení z oznámení, protože taková logika bude implementována na jednom místě. Zůstává ale potřeba zpracovat objekt Notification a extrahovat z něj potřebné parametry – to znamená, že musíte implementovat dvě zbývající metody protokolu KeyboardObservable.
K vyřešení tohoto problému jsme poskytli protokoly, označené v diagramu jako KeyboardPresentable. Mohou vypadat takto:
veřejný protokol CommonKeyboardPresentable: class
Chcete-li použít protokol, musíte uvést, že ViewController, kromě KeyboardObservable, také vyhovuje protokolu CommonKeyboardPresentable, a implementovat jeho metody.
Protokol CommonKeyboardPresentable má rozšíření, které implementuje dvě zbývající metody protokolu KeyboardObservable. V okamžiku jejich volání jsou z objektu Notification extrahovány potřebné parametry a jsou volány odpovídající metody protokolu CommonKeyboardPresentable.
Nyní nemusíte kopírovat a vkládat logiku zpracování dat z oznámení – bude implementována na jednom místě. Zároveň zůstává možnost rozšířit mechanismus a napsat si vlastní KeyboardPresentable , ve kterém budou mít metody parametry, které potřebujete.
Zvláštní pozornost si zaslouží způsob uložení objektu pozorovatele do paměti. V diagramu je jeho úložiště označeno jako Pool.
- Pool je úložiště pozorovatelů, které s každým z nich drží silnou vazbu a nedovoluje jim opustit paměť.
- Každý pozorovatel má slabé spojení s ViewControllerem, pro který byl vytvořen.
- Tím se nám podařilo vyhnout se referenčnímu cyklu mezi ViewControllerem a jeho odpovídajícím pozorovatelem.
- Zůstává problém „osiřelých“ pozorovatelů, kdy objekt pozorovatele bude obsahovat view == nula. Toto je případ, kdy ViewController zemřel, ale pozorovatel zůstal. Problém je vyřešen pravidelným čištěním fondu takových objektů.
Výsledkem je flexibilní systém, který nevyžaduje zapamatování velkého množství konstant a psaní velkých kusů identického kódu. Vše, co musíte udělat:
- Prohlaste, že ViewController podporuje protokol KeyboardObservable.
- Opravte chyby, které se objevily v Xcode implementací dvou metod tohoto protokolu.
- Nebo deklarujte, že ViewController podporuje protokol SpecificKeyboardPresentable a implementujte jeho metody.
Struktura třídy může vypadat takto:
final class ViewController: UIViewController, KeyboardObservable < . >extension ViewController: CommonKeyboardPresentable < func keyboardWillBeShown(keyboardHeight: CGFloat, duration: TimeInterval) < // do something useful >func keyboardWillBeHidden(duration: TimeInterval) < // do something useful >>
Zároveň jako SpecificKeyboardPresentable můžete použít hotové protokoly, které utilita obsahuje (například CommonKeyboardPresentable), nebo si napsat vlastní. Stačí, aby vyhovoval protokolu KeyboardObservable a implementoval dvě metody, které ve výchozí implementaci nejsou.
Jako bonus struktura KeyboardInfo zjednodušuje práci se slovníkem userInfo upozornění:
extension Notification < public struct KeyboardInfo < public var frameBegin: CGRect? public var animationCurve: UInt? public var animationDuration: Double? public var frameEnd: CGRect? >public var keyboardInfo: KeyboardInfo >
Výsledek: mínus stovky řádků naprosto identického kódu
Díky utilitě se mírně snížilo množství kódu na jedné obrazovce: asi o 15 řádků. Ale na aplikacích s velkým počtem obrazovek jsme odstranili asi 1000 řádků naprosto identického kódu!
A nejdůležitější věc: nyní si nemusíte pokaždé pamatovat názvy notifikačních klíčů. Nemusíte si ani pamatovat názvy metod z protokolů: Xcode vám nabídne vložení deklarací chybějících metod. Zbývá jen přidat implementaci.
Kompletní kód pro tento a další nástroje je v úložišti Surf.
Další užitečné informace o iOS najdete v našem telegramovém kanálu Surf iOS Team. Zveřejňujeme případy, osvědčené postupy, novinky a volná místa pro surfování. Připojte se >>