Saya memiliki set topeng berikut:
self.login.affineFormats = [
"{+7} ([000]) [000] [00] [00]",
"{8} ([000]) [000]-[00]-[00]"
]
Ketika saya mengetik nomor telepon dengan topeng +7 dan kemudian mengedit nilainya di dalam ([000]) topeng beralih ke 8 alih-alih +7 dan kemudian 7 dimasukkan ke dalam ([000])
Mungkin ada cara untuk "mengunci" topeng di textField setelah diinisialisasi dengan topeng apa pun?
Hai @MrJox , terima kasih atas laporannya.
Bisakah Anda memberikan status teks yang tepat di dalam bidang teks Anda saat kesalahan ini terjadi?
Saya akan dapat melacaknya nanti hari ini dan kemudian membantu Anda dengan solusinya.
Tidak sepenuhnya yakin apa yang Anda maksud dengan negara bagian, tetapi inilah yang terjadi:
Saya memiliki nomor telepon yang dibaca dari cache dan dimasukkan ke dalam textField (Ini adalah textField JVFloat khusus).
Nomor teleponnya adalah +7 (926) 000-00-00 dan kemudian saya mengatur penunjuk setelah '2' dan menghapus nomor ini. Akibatnya, konten textView saya diubah menjadi 8 (796) 000-00-00.
Jadi untuk beberapa alasan itu menghapus + dan memperlakukan 7 bukan sebagai topeng tetapi sebagai bagian sebenarnya dari nomor telepon dan memasukkannya ke dalam tanda kurung dan kemudian menambahkan topeng 8.
Ya, deskripsi Anda berfungsi untuk saya, terima kasih!
Tetap disini.
@MrJox saat saya sedang mengerjakan beberapa peningkatan dan perbaikan yang diperlukan oleh pembaruan perpustakaan terakhir kami, saya telah mengumpulkan solusi cepat untuk masalah Anda.
Secara efektif, ini adalah modifikasi PolyMaskTextFieldDelegate
dengan metode penghitungan afinitas khusus. Alih-alih afinitas teks keseluruhan dengan topeng, metode ini membandingkan panjang persimpangan awalan, jumlah karakter.
Kode ini atau versi modifikasinya mungkin menemukan jalannya ke sumber perpustakaan pada akhirnya.
import Foundation
import UIKit
import InputMask
<strong i="10">@IBDesignable</strong>
class PrefixAffinityMaskedTextFieldDelegate: MaskedTextFieldDelegate {
public var affineFormats: [String]
public init(primaryFormat: String, affineFormats: [String]) {
self.affineFormats = affineFormats
super.init(format: primaryFormat)
}
public override init(format: String) {
self.affineFormats = []
super.init(format: format)
}
override open func put(text: String, into field: UITextField) {
let mask: Mask = pickMask(
forText: text,
caretPosition: text.endIndex,
autocomplete: autocomplete
)
let result: Mask.Result = mask.apply(
toText: CaretString(
string: text,
caretPosition: text.endIndex
),
autocomplete: autocomplete
)
field.text = result.formattedText.string
field.caretPosition = result.formattedText.string.distance(
from: result.formattedText.string.startIndex,
to: result.formattedText.caretPosition
)
listener?.textField?(field, didFillMandatoryCharacters: result.complete, didExtractValue: result.extractedValue)
}
override open func deleteText(inRange range: NSRange, inTextInput field: UITextInput) -> Mask.Result {
let text: String = replaceCharacters(
inText: field.allText,
range: range,
withCharacters: ""
)
let mask: Mask = pickMask(
forText: text,
caretPosition: text.index(text.startIndex, offsetBy: range.location),
autocomplete: false
)
let result: Mask.Result = mask.apply(
toText: CaretString(
string: text,
caretPosition: text.index(text.startIndex, offsetBy: range.location)
),
autocomplete: false
)
field.allText = result.formattedText.string
field.caretPosition = range.location
return result
}
override open func modifyText(
inRange range: NSRange,
inTextInput field: UITextInput,
withText text: String
) -> Mask.Result {
let updatedText: String = replaceCharacters(
inText: field.allText,
range: range,
withCharacters: text
)
let mask: Mask = pickMask(
forText: updatedText,
caretPosition: updatedText.index(updatedText.startIndex, offsetBy: field.caretPosition + text.count),
autocomplete: autocomplete
)
let result: Mask.Result = mask.apply(
toText: CaretString(
string: updatedText,
caretPosition: updatedText.index(updatedText.startIndex, offsetBy: field.caretPosition + text.count)
),
autocomplete: autocomplete
)
field.allText = result.formattedText.string
field.caretPosition = result.formattedText.string.distance(
from: result.formattedText.string.startIndex,
to: result.formattedText.caretPosition
)
return result
}
func pickMask(forText text: String, caretPosition: String.Index, autocomplete: Bool) -> Mask {
let primaryAffinity: Int = calculateAffinity(
ofMask: mask,
forText: text,
caretPosition: caretPosition,
autocomplete: autocomplete
)
var masks: [(Mask, Int)] = affineFormats.map { (affineFormat: String) -> (Mask, Int) in
let mask: Mask = try! Mask.getOrCreate(withFormat: affineFormat, customNotations: customNotations)
let affinity: Int = calculateAffinity(
ofMask: mask,
forText: text,
caretPosition: caretPosition,
autocomplete: autocomplete
)
return (mask, affinity)
}
masks.sort { (left: (Mask, Int), right: (Mask, Int)) -> Bool in
return left.1 > right.1
}
var insertIndex: Int = -1
for (index, maskAffinity) in masks.enumerated() {
if primaryAffinity >= maskAffinity.1 {
insertIndex = index
break
}
}
if (insertIndex >= 0) {
masks.insert((mask, primaryAffinity), at: insertIndex)
} else {
masks.append((mask, primaryAffinity))
}
return masks.first!.0
}
func calculateAffinity(
ofMask mask: Mask,
forText text: String,
caretPosition: String.Index,
autocomplete: Bool
) -> Int {
return mask.apply(
toText: CaretString(
string: text,
caretPosition: caretPosition
),
autocomplete: autocomplete
).formattedText.string.prefixIntersection(with: text).count
}
func replaceCharacters(inText text: String, range: NSRange, withCharacters newText: String) -> String {
if 0 < range.length {
let result = NSMutableString(string: text)
result.replaceCharacters(in: range, with: newText)
return result as String
} else {
let result = NSMutableString(string: text)
result.insert(newText, at: range.location)
return result as String
}
}
}
extension String {
func prefixIntersection(with string: String) -> Substring {
let lhsStartIndex = startIndex
var lhsEndIndex = startIndex
let rhsStartIndex = string.startIndex
var rhsEndIndex = string.startIndex
while (self[lhsStartIndex...lhsEndIndex] == string[rhsStartIndex...rhsEndIndex]) {
lhsEndIndex = lhsEndIndex != endIndex ? index(after: lhsEndIndex) : endIndex
rhsEndIndex = rhsEndIndex != string.endIndex ? string.index(after: rhsEndIndex) : endIndex
if (lhsEndIndex == endIndex || rhsEndIndex == string.endIndex) {
return self[lhsStartIndex..<lhsEndIndex]
}
}
return self[lhsStartIndex..<lhsEndIndex]
}
}
extension UITextInput {
var allText: String {
get {
guard let all: UITextRange = allTextRange
else { return "" }
return self.text(in: all) ?? ""
}
set(newText) {
guard let all: UITextRange = allTextRange
else { return }
self.replace(all, withText: newText)
}
}
var caretPosition: Int {
get {
if let responder = self as? UIResponder {
// Workaround for non-optional `beginningOfDocument`, which could actually be nil if field doesn't have focus
guard responder.isFirstResponder
else { return allText.count }
}
if let range: UITextRange = selectedTextRange {
let selectedTextLocation: UITextPosition = range.start
return offset(from: beginningOfDocument, to: selectedTextLocation)
} else {
return 0
}
}
set(newPosition) {
if let responder = self as? UIResponder {
// Workaround for non-optional `beginningOfDocument`, which could actually be nil if field doesn't have focus
guard responder.isFirstResponder
else { return }
}
if newPosition > allText.count {
return
}
let from: UITextPosition = position(from: beginningOfDocument, offset: newPosition)!
let to: UITextPosition = position(from: from, offset: 0)!
selectedTextRange = textRange(from: from, to: to)
}
}
var allTextRange: UITextRange? {
return self.textRange(from: self.beginningOfDocument, to: self.endOfDocument)
}
}
Hm, jadi sekarang saya melakukan ini:
<strong i="6">@IBOutlet</strong> var loginListener: PrefixAffinityMaskedTextFieldDelegate!
Tapi itu tetap tidak akan berhasil. Apa yang saya perhatikan, jika Anda menghapus digit dalam tanda kurung dengan tombol Del, digit tersebut akan dihapus dan sekarang satu digit lebih sedikit di dalam tanda kurung namun ketika saya menghapus dengan tombol Backspace, itu menempatkan/memindahkan digit dari kiri atau digit dari kanan jadi jumlah digit di dalam kurung tetap tidak berubah.
Apa yang saya maksud:
asli: +7 (916) 000-00-00
dengan kunci del: +7 (96) 000-00-00
dengan tombol spasi mundur: 8 (796) 000-00-00
Koreksi:
Sekarang tampaknya berfungsi, namun ketika saya mencoba menghapus string di textField, saya hanya memiliki karakter '+' yang tersisa dan kemudian aplikasi saya mogok ketika saya mencoba menghapusnya dengan
Utas 1: Kesalahan fatal: tidak dapat bertambah melampaui indeks akhir
@MrJox Saya tidak yakin saya mengerti Anda dengan benar.
Perhatikan, tidak ada kunci Del
di iOS, hanya Backspace
. Jangan biarkan emulasi keyboard virtual menipu Anda.
Mengenai kesalahan terakhir Anda, Anda dapat mempertimbangkan tambalan berikut untuk kasus tepi:
extension String {
func prefixIntersection(with string: String) -> Substring {
guard !self.isEmpty && !string.isEmpty
else { return "" }
let lhsStartIndex = startIndex
var lhsEndIndex = startIndex
let rhsStartIndex = string.startIndex
var rhsEndIndex = string.startIndex
while (self[lhsStartIndex...lhsEndIndex] == string[rhsStartIndex...rhsEndIndex]) {
lhsEndIndex = lhsEndIndex != endIndex ? index(after: lhsEndIndex) : endIndex
rhsEndIndex = rhsEndIndex != string.endIndex ? string.index(after: rhsEndIndex) : endIndex
if (lhsEndIndex == endIndex || rhsEndIndex == string.endIndex) {
return self[lhsStartIndex..<lhsEndIndex]
}
}
return self[lhsStartIndex..<lhsEndIndex]
}
}
Ya sudah diperbaiki, terima kasih!
@MrJox Saya akan menutup masalah ini dengan pembaruan perpustakaan berikutnya.
Saya sedang mempertimbangkan untuk menambahkan ini ke sumber perpustakaan sebagai strategi alternatif.
@MrJox dioptimalkan & versi yang disederhanakan:
extension String {
func prefixIntersection(with string: String) -> Substring {
var lhsIndex = startIndex
var rhsIndex = string.startIndex
while lhsIndex != endIndex && rhsIndex != string.endIndex {
if self[...lhsIndex] == string[...rhsIndex] {
lhsIndex = index(after: lhsIndex)
rhsIndex = string.index(after: rhsIndex)
} else {
return self[..<lhsIndex]
}
}
return self[..<lhsIndex]
}
}
4.0.0
berisi ini sebagai fitur.
Komentar yang paling membantu
Ya sudah diperbaiki, terima kasih!