.t9String.contains(t9String) }) } class func findWith(str: String) -> [PhoneContact] { return PhoneContactStore.instance .dataSource.filter({

Как да внедрим T9 Search в iOS



Преди няколко години работех над приложение, наречено „ BOG mBank - Мобилно банкиране ”С моя екип за iOS / Android. В приложението има основна функция, където можете да използвате функцията за мобилно банкиране, за да попълните собственото си следплатено салдо на мобилен телефон или баланс на мобилен телефон на всеки контакт.

Докато разработвахме този модул, забелязахме, че е много по-лесно да се намери определен контакт във версията на приложението за Android, отколкото в iOS. Защо? Основната причина за това е търсенето с T9, което липсва в устройствата на Apple.



Нека да обясним какво представлява T9 и защо вероятно не е станал част от iOS и как iOS разработчици може да го приложи, ако е необходимо.



Какво е T9?

Т9 е технология за предсказуем текст за мобилни телефони, по-специално тези, които съдържат физическа цифрова клавиатура 3x4.



Илюстрация на T9 търсене на цифрова клавиатура

T9 първоначално е разработен от Tegic Communications , а името означава Текст на 9 клавиша .



Можете да предположите защо T9 вероятно никога не е стигнал до iOS. По време на революцията на смартфоните, въвеждането на T9 остаря, тъй като съвременните смартфони разчитаха на пълни клавиатури, благодарение на техните сензорни дисплеи. Тъй като Apple никога не е имала телефони с физически клавиатури и не е участвала в телефонния бизнес по време на разцвета на T9, разбираемо е, че тази технология е пропусната от iOS.

T9 все още се използва на определени евтини телефони без сензорен екран (така наречените телефони с функции). Въпреки това, въпреки факта, че повечето телефони с Android никога не са разполагали с физически клавиатури, съвременните устройства с Android разполагат с поддръжка за въвеждане на T9, която може да се използва за набиране на контакти чрез изписване на името на контакта, който човек се опитва да извика.



Пример за T9 предсказуемо въвеждане в действие

На телефон с цифрова клавиатура, всеки път, когато се натисне клавиш (1-9) (когато е в текстово поле), алгоритъмът връща предположение кои букви са най-вероятни за бутоните, натиснати до тази точка.

Екранна снимка на Xcode



Например, за да въведе думата „the“, потребителят ще натисне 8, след това 4, след това 3, а дисплеят ще покаже „t“, след това „th“ и след това „the“. Ако е предназначена по-рядко срещаната дума „fore“ (3673), алгоритъмът за предсказване може да избере „Ford“. Натискането на бутона „следващ“ (обикновено бутон „*“) може да изведе „доза“ и накрая „fore“. Ако е избрано „fore“, следващият път, когато потребителят натисне последователността 3673, fore е по-вероятно да бъде първата показана дума. Ако думата „Felix“ е предназначена обаче, при въвеждане на 33549, дисплеят показва „E“, след това „De“, „Del“, „Deli“ и „Felix“.

Това е пример за промяна на буква при въвеждане на думи.



Програмно използване на T9 в iOS

Така че, нека се потопим в тази функция и напишем лесен пример за въвеждане на T9 за iOS. На първо място, трябва да създадем нов проект.

Необходимите предпоставки за нашия проект са основни: Инструменти за изграждане на Xcode и Xcode, инсталирани на вашия Mac.



За да създадете нов проект, отворете Приложение Xcode на вашия Mac и изберете „Създаване на нов проект Xcode“, след това дайте име на проекта си и изберете типа на приложението, което ще бъде създадено. Просто изберете “Single View App” и натиснете Next.

Екранна снимка на Xcode

На следващия екран, както виждате, ще има информация, която трябва да предоставите.

Забележка: Ако нямате акаунт на програмист, можете да го стартирате и на Simulator.

Натиснете бутона Next и сме готови да започнем.

Проста архитектура

Както вече знаете, когато създавате ново приложение, вече имате MainViewController клас и Main.Storyboard. За целите на тестването, разбира се, можем да използваме този контролер.

Преди да започнем да проектираме нещо, нека първо създадем всички необходими класове и файлове, за да сме сигурни, че сме настроили и изпълнили всичко, за да преминем към UI частта на задачата.

Просто някъде във вашия проект просто създайте нов файл, наречен „ PhoneContactsStore.swift ”В моя случай изглежда така.

T9 търсене на бордове и архитектура

Първият ни бизнес е да създадем карта с всички варианти на цифрови клавиатурни входове.

import Contacts import UIKit fileprivate let T9Map = [ ' ' : '0', 'a' : '2', 'b' : '2', 'c' : '2', 'd' : '3', 'e' : '3', 'f' : '3', 'g' : '4', 'h' : '4', 'i' : '4', 'j' : '5', 'k' : '5', 'l' : '5', 'm' : '6', 'n' : '6', 'o' : '6', 'p' : '7', 'q' : '7', 'r' : '7', 's' : '7', 't' : '8', 'u' : '8', 'v' : '8', 'w' : '9', 'x' : '9', 'y' : '9', 'z' : '9', '0' : '0', '1' : '1', '2' : '2', '3' : '3', '4' : '4', '5' : '5', '6' : '6', '7' : '7', '8' : '8', '9' : '9' ]

Това е. Приложихме пълната карта с всички варианти. Сега да продължим да създаваме първия си клас, наречен „ PhoneContact . '

Вашият файл трябва да изглежда така:

алтернативен текст на изображението

Първо, в този клас трябва да се уверим, че имаме Regex филтър от A-Z + 0-9.

private let regex = try! NSRegularExpression(pattern: '[^ a-z()0-9+]', options: .caseInsensitive)

По принцип потребителят има свойства по подразбиране, които трябва да бъдат показани:

var firstName : String! var lastName : String! var phoneNumber : String! var t9String : String = '' var image : UIImage? var fullName: String! { get { return String(format: '%@ %@', self.firstName, self.lastName) } }

Уверете се, че сте заменили hash и isEqual за да зададете вашата персонализирана логика за филтриране на списъци

Също така трябва да имаме метода за замяна, за да избегнем каквото и да било освен числата в низа.

override var hash: Int { get { return self.phoneNumber.hash } } override func isEqual(_ object: Any?) -> Bool { if let obj = object as? PhoneContact { return obj.phoneNumber == self.phoneNumber } return false } private func replace(str : String) -> String { let range = NSMakeRange(0, str.count) return self.regex.stringByReplacingMatches(in: str, options: [], range: range, withTemplate: '') }

Сега се нуждаем от още един метод, наречен calculateT9, за да намерим контакти, свързани с fullname или phonenumber.

func calculateT9() { for c in self.replace(str: self.fullName) { t9String.append(T9Map[String(c).localizedLowercase] ?? String(c)) } for c in self.replace(str: self.phoneNumber) { t9String.append(T9Map[String(c).localizedLowercase] ?? String(c)) } }

След прилагане на PhoneContact обект, трябва да съхраним контактите си някъде в паметта. За тази цел ще създам нов клас, наречен PhoneContactStore.

Ще имаме два местни имота:

fileprivate let contactsStore = CNContactStore()

И:

fileprivate lazy var dataSource = Set()

Използвам Set за да се уверите, че няма дублиране по време на попълването на този източник на данни.

final class PhoneContactStore { fileprivate let contactsStore = CNContactStore() fileprivate lazy var dataSource = Set() static let instance : PhoneContactStore = { let instance = PhoneContactStore() return instance }() }

Както можете да видите, това е клас на Singleton, което означава, че го пазим в паметта, докато приложението не стартира. За повече информация относно Singletons или дизайнерски модели можете да прочетете тук .

Сега сме много близо до финализиране на търсенето в T9.

Сглобяване на всичко

Преди да влезете в списъка с контакти в Apple, първо трябва да поискате разрешение.

class func hasAccess() -> Bool { let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts) return authorizationStatus == .authorized } class func requestForAccess(_ completionHandler: @escaping (_ accessGranted: Bool, _ error : CustomError?) -> Void) { let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts) switch authorizationStatus { case .authorized: self.instance.loadAllContacts() completionHandler(true, nil) case .denied, .notDetermined: weak var wSelf = self.instance self.instance.contactsStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in var err: CustomError? if let e = accessError { err = CustomError(description: e.localizedDescription, code: 0) } else { wSelf?.loadAllContacts() } completionHandler(access, err) }) default: completionHandler(false, CustomError(description: 'Common Error', code: 100)) } }

След като сме упълномощили достъпа до контакти, можем да напишем метода, за да получим списъка от системата.

fileprivate func loadAllContacts() { if self.dataSource.count == 0 { let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactThumbnailImageDataKey, CNContactPhoneNumbersKey] do { let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor]) request.sortOrder = .givenName request.unifyResults = true if #available(iOS 10.0, *) { request.mutableObjects = false } else {} // Fallback on earlier versions try self.contactsStore.enumerateContacts(with: request, usingBlock: {(contact, ok) in DispatchQueue.main.async { for phone in contact.phoneNumbers { let local = PhoneContact() local.firstName = contact.givenName local.lastName = contact.familyName if let data = contact.thumbnailImageData { local.image = UIImage(data: data) } var phoneNum = phone.value.stringValue let strArr = phoneNum.components(separatedBy: CharacterSet.decimalDigits.inverted) phoneNum = NSArray(array: strArr).componentsJoined(by: '') local.phoneNumber = phoneNum local.calculateT9() self.dataSource.insert(local) } } }) } catch {} } }

Вече сме заредили списъка с контакти в паметта, което означава, че вече можем да напишем прост метод:

  1. findWith - t9String
  2. findWith - str
class func findWith(t9String: String) -> [PhoneContact] { return PhoneContactStore.instance.dataSource.filter({ $0.t9String.contains(t9String) }) } class func findWith(str: String) -> [PhoneContact] { return PhoneContactStore.instance .dataSource.filter({ $0.fullName.lowercased() .contains(str.lowercased()) }) } class func count() -> Int { let request = CNContactFetchRequest(keysToFetch: []) var count = 0; do { try self.instance.contactsStore.enumerateContacts( with: request, usingBlock: {(contact, ok) in count += 1; }) } catch {} return count }

Това е. Готови сме.

Сега можем да използваме T9 търсене вътре UIViewController.

fileprivate let cellIdentifier = 'contact_list_cell' final class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var searchBar: UISearchBar! fileprivate lazy var dataSource = [PhoneContact]() fileprivate var searchString : String? fileprivate var searchInT9 : Bool = true override func viewDidLoad() { super.viewDidLoad() self.tableView.register( UINib( nibName: 'ContactListCell', bundle: nil ), forCellReuseIdentifier: 'ContactListCell' ) self.searchBar.keyboardType = .numberPad PhoneContactStore.requestForAccess { (ok, err) in } } func filter(searchString: String, t9: Bool = true) { } func reloadListSection(section: Int, animation: UITableViewRowAnimation = .none) { } }

Изпълнение на метода на филтъра:

func filter(searchString: String, t9: Bool = true) { self.searchString = searchString self.searchInT9 = t9 if let str = self.searchString { if t9 { self.dataSource = PhoneContactStore.findWith(t9String: str) } else { self.dataSource = PhoneContactStore.findWith(str: str) } } else { self.dataSource = [PhoneContact]() } self.reloadListSection(section: 0) }

Прилагане на метода на списъка за презареждане:

func reloadListSection(section: Int, animation: UITableViewRowAnimation = .none) { if self.tableView.numberOfSections <= section { self.tableView.beginUpdates() self.tableView.insertSections(IndexSet(integersIn:0..

И ето последната част от нашия кратък урок, UITableView изпълнение:

extension ViewController: UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return tableView.dequeueReusableCell(withIdentifier: 'ContactListCell')! } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.dataSource.count } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let contactCell = cell as? ContactListCell else { return } let row = self.dataSource[indexPath.row] contactCell.configureCell( fullName: row.fullName, t9String: row.t9String, number: row.phoneNumber, searchStr: searchString, img: row.image, t9Search: self.searchInT9 ) } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 55 } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { self.filter(searchString: searchText) } }

Обобщавайки

Това завършва нашия урок за търсене на T9 и се надяваме, че сте го намерили просто и лесно за внедряване в iOS.

Но защо трябва? И защо Apple не включи поддръжката на T9 в iOS за начало? Както посочихме във въведението, T9 едва ли е убийствена функция на съвременните телефони - това е по-скоро последваща мисъл, връщане назад към дните на „тъпите“ телефони с механични цифрови подложки.

Все още обаче има няколко основателни причини, поради които трябва да приложите търсене на T9 в определени сценарии, или за последователност, или за подобряване на достъпността и потребителския опит. По-весело, ако сте носталгичният вид, играта с входа на T9 може да върне приятни спомени от ученическите ви дни.

И накрая, можете да намерите пълния код за внедряване на T9 в iOS на моя GitHub репо .

Разбиране на основите

Какво е предсказуем текст?

Предсказуем текст е технология за въвеждане, при която един клавиш или бутон представлява много букви, например на цифрови клавиатури, използвани на по-стари мобилни телефони. Той се използва и за подобряване на достъпността в определени сценарии.

Защо Т9 се нарича така?

T9 означава Текст на 9 клавиша, тъй като разчита на 9-цифрена цифрова клавиатура за въвеждане на текст.

Как да използвам T9 на клавиатурата си?

Ето един бърз пример. За „ЗДРАВЕ“ ще трябва да натиснете само 4-3-5-5-6. Това са цифрите, съдържащи буквите, които пишат „ЗДРАВЕЙТЕ“.

.fullName.lowercased() .contains(str.lowercased()) }) } class func count() -> Int { let request = CNContactFetchRequest(keysToFetch: []) var count = 0; do { try self.instance.contactsStore.enumerateContacts( with: request, usingBlock: {(contact, ok) in count += 1; }) } catch {} return count }

Това е. Готови сме.

Сега можем да използваме T9 търсене вътре UIViewController.

fileprivate let cellIdentifier = 'contact_list_cell' final class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var searchBar: UISearchBar! fileprivate lazy var dataSource = [PhoneContact]() fileprivate var searchString : String? fileprivate var searchInT9 : Bool = true override func viewDidLoad() { super.viewDidLoad() self.tableView.register( UINib( nibName: 'ContactListCell', bundle: nil ), forCellReuseIdentifier: 'ContactListCell' ) self.searchBar.keyboardType = .numberPad PhoneContactStore.requestForAccess { (ok, err) in } } func filter(searchString: String, t9: Bool = true) { } func reloadListSection(section: Int, animation: UITableViewRowAnimation = .none) { } }

Изпълнение на метода на филтъра:

func filter(searchString: String, t9: Bool = true) { self.searchString = searchString self.searchInT9 = t9 if let str = self.searchString { if t9 { self.dataSource = PhoneContactStore.findWith(t9String: str) } else { self.dataSource = PhoneContactStore.findWith(str: str) } } else { self.dataSource = [PhoneContact]() } self.reloadListSection(section: 0) }

Прилагане на метода на списъка за презареждане:

func reloadListSection(section: Int, animation: UITableViewRowAnimation = .none) { if self.tableView.numberOfSections <= section { self.tableView.beginUpdates() self.tableView.insertSections(IndexSet(integersIn:0..

И ето последната част от нашия кратък урок, UITableView изпълнение:

extension ViewController: UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return tableView.dequeueReusableCell(withIdentifier: 'ContactListCell')! } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.dataSource.count } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let contactCell = cell as? ContactListCell else { return } let row = self.dataSource[indexPath.row] contactCell.configureCell( fullName: row.fullName, t9String: row.t9String, number: row.phoneNumber, searchStr: searchString, img: row.image, t9Search: self.searchInT9 ) } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 55 } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { self.filter(searchString: searchText) } }

Обобщавайки

Това завършва нашия урок за търсене на T9 и се надяваме, че сте го намерили просто и лесно за внедряване в iOS.

Но защо трябва? И защо Apple не включи поддръжката на T9 в iOS за начало? Както посочихме във въведението, T9 едва ли е убийствена функция на съвременните телефони - това е по-скоро последваща мисъл, връщане назад към дните на „тъпите“ телефони с механични цифрови подложки.

Все още обаче има няколко основателни причини, поради които трябва да приложите търсене на T9 в определени сценарии, или за последователност, или за подобряване на достъпността и потребителския опит. По-весело, ако сте носталгичният вид, играта с входа на T9 може да върне приятни спомени от ученическите ви дни.

И накрая, можете да намерите пълния код за внедряване на T9 в iOS на моя GitHub репо .

Разбиране на основите

Какво е предсказуем текст?

Предсказуем текст е технология за въвеждане, при която един клавиш или бутон представлява много букви, например на цифрови клавиатури, използвани на по-стари мобилни телефони. Той се използва и за подобряване на достъпността в определени сценарии.

Защо Т9 се нарича така?

T9 означава Текст на 9 клавиша, тъй като разчита на 9-цифрена цифрова клавиатура за въвеждане на текст.

Как да използвам T9 на клавиатурата си?

Ето един бърз пример. За „ЗДРАВЕ“ ще трябва да натиснете само 4-3-5-5-6. Това са цифрите, съдържащи буквите, които пишат „ЗДРАВЕЙТЕ“.