لدي مجموعة الأقنعة التالية:
self.login.affineFormats = [
"{+7} ([000]) [000] [00] [00]",
"{8} ([000]) [000]-[00]-[00]"
]
عندما أكتب رقم هاتف مع قناع +7 ثم قم بتحرير القيمة داخل ([000]) تبديل القناع إلى 8 بدلاً من +7 ثم يتم وضع 7 بالداخل ([000])
ربما توجد طريقة "لقفل" القناع في حقل النص بمجرد تهيئته بأي من الأقنعة؟
مرحبًا MrJox ، شكرًا لتقريرك.
هل يمكنك تقديم الحالات الدقيقة للنص داخل حقل النص عند حدوث هذا الخطأ؟
سأكون قادرًا على تتبعها لاحقًا اليوم ثم أساعدك في الحل.
لست متأكدًا تمامًا مما تقصده بكلمات ولكن إليك ما يحدث:
لدي رقم هاتف تمت قراءته من ذاكرة التخزين المؤقت وتم إدراجه في حقل النص (إنه حقل نصي JVFloat مخصص).
رقم الهاتف هو +7 (926) 000-00-00 ثم قمت بتعيين المؤشر بعد "2" وحذف هذا الرقم. نتيجة لذلك ، يتحول محتوى textView الخاص بي إلى 8 (796) 000-00-00.
لذلك لسبب ما ، يقوم بحذف + ومعامل 7 ليس كقناع ولكن كجزء فعلي من رقم الهاتف ويضعه بين قوسين ثم يضيف قناع 8.
نعم ، وصفك يناسبني ، شكرًا!
ابقوا متابعين.
MrJox أثناء عملي على بعض التحسينات والإصلاحات التي يتطلبها آخر تحديث للمكتبة ، قمت بتجميع حل سريع لمشكلتك.
على نحو فعال ، إنه تعديل PolyMaskTextFieldDelegate
باستخدام طريقة حساب تقارب مخصصة. بدلاً من تقارب النص الإجمالي مع القناع ، تقارن هذه الطريقة طول تقاطع البادئات ، عدد الأحرف.
قد تجد هذه الشفرة أو نسختها المعدلة طريقها إلى مصادر المكتبة في النهاية.
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)
}
}
حسنًا ، أفعل هذا الآن:
<strong i="6">@IBOutlet</strong> var loginListener: PrefixAffinityMaskedTextFieldDelegate!
لكنها ما زالت لا تعمل. ما لاحظته ، إذا قمت بحذف الأرقام الموجودة بين قوسين باستخدام مفتاح Del ، فسيتم حذف الرقم وأصبح الآن رقمًا أقل بين قوسين ، ولكن عندما أحذف باستخدام زر Backspace ، فإنه يضع / ينقل إما الرقم من اليسار أو الرقم من اليمين لذلك عدد الأرقام داخل الأقواس يبقى دون تغيير.
الذي أقصده:
الأصل: +7 (916) 000-00-00
باستخدام مفتاح del: +7 (96) 000-00-00
مع مفتاح مسافة للخلف: 8 (796) 000-00-00
تصحيح:
يبدو الآن أنه يعمل ولكن عندما أحاول حذف السلسلة في textField ، يتبقى لدي حرف "+" فقط ثم يتعطل تطبيقي عندما أحاول حذفه باستخدام
مؤشر الترابط 1: خطأ فادح: لا يمكن زيادة ما بعد endIndex
MrJox لست متأكدًا من أنني فهمتك بشكل صحيح.
لاحظ أنه لا يوجد مفتاح Del
على iOS ، فقط Backspace
. لا تدع محاكاة لوحة المفاتيح الافتراضية تخدعك.
فيما يتعلق بالخطأ الأخير ، يمكنك التفكير في التصحيح التالي لحالة الحافة:
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]
}
}
نعم لقد أصلحته ، شكرا!
MrJox سأغلق هذه المشكلة بتحديث المكتبة التالي.
أنا أفكر في إضافة هذا إلى مصادر المكتبة كاستراتيجية بديلة.
MrJox نسخة محسنة ومبسطة:
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
يحتوي على هذا كميزة.
التعليق الأكثر فائدة
نعم لقد أصلحته ، شكرا!