- 对String进行扩展,字符串增加下表索引功能
import Foundation
// インデックスを文字列に追加
extension String
{
subscript(index:Int) -> String
{
get{
return String(self[self.index(self.startIndex, offsetBy: index)])
}
set{
let tmp = self
self = ""
for (idx, item) in tmp.characters.enumerated() {
if idx == index {
self += "\(newValue)"
}else{
self += "\(item)"
}
}
}
}
}
- 提取共通部分,使得此控件可以使用于不同的需求
为了防止粘贴导致光标设置无效,需要在设置光标位置时(66, 78行)加上:
DispatchQueue.main.asyncAfter(deadline: .now()) {}
参考链接:https://stackoverflow.com/questions/53151401/how-to-place-cursor-at-the-end-of-formatted-number-after-copy-paste
import Foundation
import UIKit
class AutoFillTextField: UITextField {
// 追加記号の位置
var insertPosition:[Int]!
// 追加記号のタイプ
var insertStr: String!
// 最大長
var maxStr: Int!
// カーソル位置
var cursorPostionOffset: Int!
// 前回のテキスト内容
var previousText: String!
// 前回のレンジ
var previousRange: UITextRange!
override init(frame: CGRect) {
super.init(frame: frame)
setupField()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupField()
}
private func setupField() {
// 数字キーボードのタイプを設定
self.keyboardType = .numberPad
//テキストフィールド値変更の監視
self.addTarget(self, action: #selector(format), for: .editingChanged)
}
@objc func format() {
// 現在のカーソル位置
var cursorPostion = self.offset(from: self.beginningOfDocument, to: self.selectedTextRange!.start)
// 数字を取得
let digitsText = getDigitsText(string: self.text!, cursorPosition: &cursorPostion)
// 最大長の制限
if digitsText.count > maxStr {
let str = digitsText.prefix(maxStr)
self.text = getHyphenOrSpaceText(string: String(str), cursorPosition: &cursorPostion, insertPosition: insertPosition, insertStr: insertStr)
if cursorPostion < maxStr + insertPosition.count {
cursorPostionOffset = cursorPostion
} else {
cursorPostionOffset = maxStr + insertPosition.count
}
let targetPostion = self.position(from: self.beginningOfDocument, offset: cursorPostionOffset)!
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.selectedTextRange = self.textRange(from: targetPostion, to: targetPostion)
}
return
}
// 文字列に区切り記号を追加
let hyphenText = getHyphenOrSpaceText(string: digitsText, cursorPosition: &cursorPostion, insertPosition: insertPosition, insertStr: insertStr)
self.text = hyphenText
// カーソル位置を設定
let targetPostion = self.position(from: self.beginningOfDocument, offset: cursorPostion)!
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.selectedTextRange = self.textRange(from: targetPostion, to: targetPostion)
}
previousText = self.text!
previousRange = self.selectedTextRange!
}
// 数字を取得
private func getDigitsText(string: String, cursorPosition:inout Int) -> String {
// カーソル開始位置を記録
let originalCursorPosition = cursorPosition
var result = ""
var i = 0
for uni in string.unicodeScalars {
if CharacterSet.decimalDigits.contains(uni) {
result.append(string[i])
} else {
// リセットカーソル位置
if i < originalCursorPosition {
cursorPosition = cursorPosition - 1
}
}
i = i + 1
}
return result
}
// 文字列に区切り記号を追加
private func getHyphenOrSpaceText(string: String, cursorPosition:inout Int, insertPosition: [Int], insertStr: String) -> String {
// カーソル開始位置を記録
let originalCursorPosition = cursorPosition
var result = ""
for i in 0 ..< string.count {
for j in 0 ..< insertPosition.endIndex {
if i == insertPosition[j] {
result.append(insertStr)
// リセットカーソル位置
if i < originalCursorPosition {
cursorPosition = cursorPosition + 1
}
}
}
result.append(string[i])
}
return result
}
}
- 定义电话号码的UI控件
如果要适应不同的需求,只需要更改setValue()
中的值即可
import Foundation
import UIKit
/// 010-1234-5678型の電話番号を整形
class PhoneNumTextField: AutoFillTextField {
override init(frame: CGRect) {
super.init(frame: frame)
setValue()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setValue()
}
func setValue() {
// 追加記号の位置
self.insertPosition = [3, 7]
// 追加記号のタイプ
self.insertStr = "-"
// 最大長
self.maxStr = 11
}
}