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

T9-otsingu rakendamine iOS-is

Paar aastat tagasi töötasin rakenduse nimega “ BOG mBank - mobiilipank ”Minu iOS / Androidi meeskonnaga. Rakenduses on põhifunktsioon, kus saate mobiilipanga funktsionaalsuse abil täiendada oma mobiiltelefoni järelmaksusaldo või mõne kontakti mobiilisaldo.

Selle mooduli väljatöötamisel märkasime, et konkreetse kontakti leidmine on rakenduse Android-versioonis palju lihtsam kui iOS-is. Miks? Selle peamine põhjus on T9 otsing, mis Apple'i seadmetest puudub.



Selgitame, mis on T9 ja miks see tõenäoliselt iOS-i osaks ei saanud ja kuidas iOS-i arendajad saab seda vajadusel rakendada.



Mis on T9?

T9 on sõnastikupõhine tekstitehnoloogia mobiiltelefonidele, eriti neile, mis sisaldavad füüsilist 3x4 numbriklaviatuuri.

T9 otsingu illustratsioon numbriklahvistikul



T9 töötas algselt välja Tegic Communications ja nimi tähistab Tekst 9 võtmel .

Võite arvata, miks T9 tõenäoliselt kunagi iOS-i ei jõudnud. Nutitelefonide revolutsiooni ajal muutus T9 sisend vananenuks, kuna tänapäevased nutitelefonide telefonid tuginesid puutetundliku ekraaniga viisakalt täisklaviatuuridele. Kuna Apple'il ei olnud kunagi füüsiliste klaviatuuridega telefone ega olnud T9 hiilgeajal telefonifirmas, on arusaadav, et see tehnoloogia jäeti iOS-ist välja.

T9-d kasutatakse endiselt teatud odavatel, puutetundliku ekraanita telefonidel (nn funktsioonitelefonid). Hoolimata asjaolust, et enamikul Android-telefonidest ei olnud kunagi füüsilisi klaviatuure, on tänapäevastes Android-seadmetes T9-sisendi tugi, mida saab kasutada kontaktide valimiseks, kirjutades kontakti nime, kellele üritatakse helistada.



Näide T9 ennustava sisendi toimimisest

Numbriklahvistikuga telefonis tagastab algoritm iga kord, kui vajutatakse klahvi (1–9) (tekstiväljal) oletus selle kohta, millised tähed on kõige tõenäolisemad selleks hetkeks vajutatud klahvide jaoks.

Xcode

Näiteks sõna „the” sisestamiseks vajutas kasutaja klahve 8, seejärel 4 ja siis 3 ning ekraanil kuvatakse „t”, siis „th” ja siis “the”. Kui on mõeldud vähem levinud sõna „ette“ (3673), võib ennustav algoritm valida „Ford”. „Järgmise“ klahvi (tavaliselt „*“ klahvi) vajutamine võib tõsta „annuse“ ja lõpuks „ette“. Kui on valitud „ette“, siis järgmine kord, kui kasutaja vajutab järjestust 3673, on esiplaan tõenäolisemalt esimene kuvatav sõna. Kui aga on mõeldud sõna „Felix”, kuvatakse ekraanil 33549 sisestades ekraanil „E”, seejärel „De”, „Del”, „Deli” ja „Felix”.

See on näide tähe muutumisest sõnade sisestamise ajal.

T9 programmeeritud kasutamine iOS-is

Niisiis, uurime seda funktsiooni ja kirjutame lihtsa näite iOS-i T9 sisendist. Kõigepealt peame looma uue projekti.

Meie projekti eeldused on põhilised: Teie Maci installitud tööriistad Xcode ja Xcode.

Uue projekti loomiseks avage oma Xcode'i rakendus oma Macis ja valige 'Loo uus Xcode-projekt', seejärel nimetage oma projekt ja valige loodava rakenduse tüüp. Valige lihtsalt „Single View App“ ja vajutage Next.

Xcode

Järgmisel ekraanil, nagu näete, on teave, mille peate esitama.

Märge: Kui teil pole arendajakontot, saate seda käivitada ka Simulatoris.

Vajutage nuppu Järgmine ja oleme alustamiseks valmis.

Lihtne arhitektuur

Nagu te juba teate, on teil uue rakenduse loomisel juba olemas MainViewController klass ja Main.Storyboard. Testimise eesmärgil saame loomulikult seda kontrollerit kasutada.

Enne kui hakkame midagi kujundama, loome kõigepealt kõik vajalikud klassid ja failid, veendumaks, et meil on kõik töö seadistatud ja töötab, et liikuda töö kasutajaliidese ossa.

Looge kuskil oma projekti sees lihtsalt uus fail nimega “ Telefonikontaktide pood.swift ”Minu puhul näeb see välja selline.

T9 otsinguplokk ja arhitektuur

Meie esimene tööjärjekord on luua kaart, millel on numbriliste klaviatuurisisendite kõik variatsioonid.

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' ]

See on kõik. Oleme rakendanud täieliku kaardi koos kõigi variatsioonidega. Nüüd jätkame oma esimese klassi loomist Telefoni kontakt . '

Teie fail peaks välja nägema järgmine:

pilt alt tekst

Esiteks peame selles klassis veenduma, et meil on Regex-filter vahemikus A-Z + 0-9.

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

Põhimõtteliselt on kasutajal vaikeatribuudid, mida tuleb kuvada:

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) } }

Veenduge, et olete alistanud hash ja isEqual loendi filtreerimiseks kohandatud loogika määramiseks.

Samuti peab meil olema asendusmeetod, et vältida stringis midagi muud kui numbreid.

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: '') }

Nüüd vajame calculateT9 -ga seotud kontaktide leidmiseks veel ühte meetodit nimega fullname või 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)) } }

Pärast PhoneContact rakendamist objekti, peame oma kontaktid kuhugi mällu salvestama. Sel eesmärgil kavatsen luua uue klassi nimega PhoneContactStore

Meil on kaks kohalikku kinnisvara:

fileprivate let contactsStore = CNContactStore()

Ja:

fileprivate lazy var dataSource = Set()

Kasutan Set veendumaks, et selle andmeallika täitmisel ei tekiks dubleerimist.

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

Nagu näete, on see Singletoni klass, mis tähendab, et hoiame seda mälus, kuni rakendus töötab. Lisateavet Singletonsi või kujundusmustrite kohta võiksite lugeda siin .

Oleme nüüd T9 otsingu lõpuleviimisele väga lähedal.

Kõike kokku panema

Enne kui pöördute Apple'i kontaktiloendisse, peate kõigepealt küsima luba.

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)) } }

Kui meil on kontaktidele juurdepääsemiseks volitus, saame kirjutada meetodi loendi saamiseks süsteemist.

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 {} } }

Oleme juba kontaktide loendi mällu laadinud, mis tähendab, et saame nüüd kirjutada lihtsa meetodi:

  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 }

See on kõik. Me saime valmis.

Nüüd saame kasutada T9 otsingut 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) { } }

Filtreerimismeetodi juurutamine:

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) }

Loendi meetodi uuesti laadimine:

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

Ja siin on meie lühikese õpetuse viimane osa UITableView rakendamine:

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) } }

Pakkimine

See lõpetab meie T9 otsinguõpetuse ja loodetavasti leidsite, et see on iOS-is lihtne ja hõlpsasti rakendatav.

Aga miks sa peaksid? Ja miks ei lisanud Apple kõigepealt iOS-i T9 tuge? Nagu me sissejuhatuses märkisime, pole T9 tänapäevastes telefonides vaevalt tapjafunktsioon - see on pigem tagantjärele mõte, tagasilöök mehaaniliste numbriklahvistikega 'tummade' telefonide päevale.

Siiski on endiselt mõned põhjendatud põhjused, miks peaksite T9 otsingu teatud stsenaariumides rakendama kas järjepidevuse huvides või juurdepääsetavuse ja kasutuskogemuse parandamiseks. Rõõmsam on see, et kui olete nostalgiline, võib T9-sisendiga mängimine tuua teie kooliajast meeldivad mälestused.

Lõpuks leiate täieliku koodi iOS-i T9 juurutamiseks aadressilt minu GitHubi repo .

Põhitõdesid mõistes

Mis on ennustav tekst?

Ennustav tekst on sisestustehnoloogia, kus üks klahv või nupp tähistab paljusid tähti, näiteks vanematel mobiiltelefonidel kasutatavatel numbriklaviatuuridel. Teatud stsenaariumides kasutatakse seda ka ligipääsetavuse parandamiseks.

Miks T9 seda nimetatakse?

T9 tähistab teksti 9 klahvil, kuna see tugineb tekstisisestuseks 9-kohalisele numbriklahvistikule.

Kuidas kasutada klaviatuuril T9?

Siin on kiire näide. Tere, et vajutate nuppu 4-3-5-5-6. Need on numbrid, mis sisaldavad tähti, mis tähistavad „TERE”.

.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 }

See on kõik. Me saime valmis.

Nüüd saame kasutada T9 otsingut 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) { } }

Filtreerimismeetodi juurutamine:

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) }

Loendi meetodi uuesti laadimine:

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

Ja siin on meie lühikese õpetuse viimane osa UITableView rakendamine:

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) } }

Pakkimine

See lõpetab meie T9 otsinguõpetuse ja loodetavasti leidsite, et see on iOS-is lihtne ja hõlpsasti rakendatav.

Aga miks sa peaksid? Ja miks ei lisanud Apple kõigepealt iOS-i T9 tuge? Nagu me sissejuhatuses märkisime, pole T9 tänapäevastes telefonides vaevalt tapjafunktsioon - see on pigem tagantjärele mõte, tagasilöök mehaaniliste numbriklahvistikega 'tummade' telefonide päevale.

Siiski on endiselt mõned põhjendatud põhjused, miks peaksite T9 otsingu teatud stsenaariumides rakendama kas järjepidevuse huvides või juurdepääsetavuse ja kasutuskogemuse parandamiseks. Rõõmsam on see, et kui olete nostalgiline, võib T9-sisendiga mängimine tuua teie kooliajast meeldivad mälestused.

Lõpuks leiate täieliku koodi iOS-i T9 juurutamiseks aadressilt minu GitHubi repo .

Põhitõdesid mõistes

Mis on ennustav tekst?

Ennustav tekst on sisestustehnoloogia, kus üks klahv või nupp tähistab paljusid tähti, näiteks vanematel mobiiltelefonidel kasutatavatel numbriklaviatuuridel. Teatud stsenaariumides kasutatakse seda ka ligipääsetavuse parandamiseks.

Miks T9 seda nimetatakse?

T9 tähistab teksti 9 klahvil, kuna see tugineb tekstisisestuseks 9-kohalisele numbriklahvistikule.

Kuidas kasutada klaviatuuril T9?

Siin on kiire näide. Tere, et vajutate nuppu 4-3-5-5-6. Need on numbrid, mis sisaldavad tähti, mis tähistavad „TERE”.