自定义UI控件:电话号码的输入时自动格式化

  1. 对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)"
                }
            }
        }
    }
}

  1. 提取共通部分,使得此控件可以使用于不同的需求

为了防止粘贴导致光标设置无效,需要在设置光标位置时(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
    }
}

  1. 定义电话号码的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
    }
}

参考链接:https://www.hangge.com/blog/cache/detail_1610.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值