原创文章转载请注明出处
默认的UITextField并没有限制字符输入个数的属性,默认的做法是通过UITextFieldDelegate的接口去判断,每个使用UITextField的文件都要添加类似的代码,完全不符合程序员偷懒的性格。
Swift的Extensions比起Objective-C强大了许多,结合运行时的关联对象(associated objects),我们就来打造一个趁手的UITextField吧。
以下部分代码参考了Github上的开源代码,感谢开源的码农。
UITextField
import Foundation
//MARK: - UITextField
extension UITextField {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UITextField.self {
return
}
dispatch_once(&Static.token) {
UITextFieldHelper.sharedInstance
}
}
private struct AssociatedKeys {
static var LimitLength = "LimitLength"
}
var limitLength: Int? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.LimitLength) as? Int
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.LimitLength,
newValue as Int?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
func changeCharactersInRange(range: NSRange, replacementString string: String) -> String {
assert((self.text! as NSString).length >= (range.location + range.length))
let headPart = (self.text! as NSString).substringToIndex(range.location)
let tailPart = (self.text! as NSString).substringFromIndex(range.location + range.length)
let newString = "\(headPart)\(string)\(tailPart)"
return newString
}
}
//MARK: - UITextFieldHelper
private let singleTone = UITextFieldHelper()
class UITextFieldHelper: NSObject {
/// 单例
class var sharedInstance : UITextFieldHelper {
return singleTone
}
override init() {
super.init()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UITextFieldHelper.textFieldViewDidChange(_:)), name: UITextFieldTextDidChangeNotification, object: nil)
}
func textFieldViewDidChange(notification: NSNotification) {
if let textField = notification.object as? UITextField {
if let limit = textField.limitLength {
if let _ = textField.markedTextRange {
//do nothing
return
}
if let text = textField.text {
if (text as NSString).length >= limit {
textField.text = (text as NSString).substringWithRange(NSMakeRange(0, limit))
textField.sendActionsForControlEvents(.EditingChanged)
}
}
}
}
}
}
如此一来,使用就非常方便了。直接设置UITextField的limitLength属性,超过设定的字符数时,会自动截取。UITextView的设置稍微有点不同,因为UITextView不支持ControlEvent。
UITextView
import Foundation
//MARK: - UITextView
extension UITextView {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UITextView.self {
return
}
dispatch_once(&Static.token) {
UITextViewHelper.sharedInstance
}
}
private struct AssociatedKeys {
static var LimitLength = "LimitLength"
}
var limitLength: Int? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.LimitLength) as? Int
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.LimitLength,
newValue as Int?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
// Placeholder text
var placeholder: String? {
get {
// Get the placeholder text from the label
var placeholderText: String?
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderText = placeholderLabel.text
}
return placeholderText
}
set {
// Store the placeholder text in the label
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderLabel.text = newValue
placeholderLabel.sizeToFit()
placeholderLabel.hidden = (self.text.length > 0)
} else {
self.addPlaceholderLabel(newValue!)
}
}
}
// Add a placeholder label to the text view
func addPlaceholderLabel(placeholderText: String) {
// Create the label and set its properties
let placeholderLabel = UILabel()
placeholderLabel.text = placeholderText
placeholderLabel.sizeToFit()
placeholderLabel.frame.origin.x = 5.0
placeholderLabel.frame.origin.y = 5.0
placeholderLabel.font = self.font
placeholderLabel.textColor = UIColor.lightGrayColor()
placeholderLabel.tag = 100
// Hide the label if there is text in the text view
placeholderLabel.hidden = (self.text.length > 0)
self.addSubview(placeholderLabel)
}
}
//MARK: - UITextViewHelper
private let singleTone = UITextViewHelper()
class UITextViewHelper: NSObject {
/// 单例
class var sharedInstance : UITextViewHelper {
return singleTone
}
override init() {
super.init()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UITextViewDelegate.textViewDidChange(_:)), name: UITextViewTextDidChangeNotification, object: nil)
}
func textViewDidChange(notification: NSNotification) {
if let textView = notification.object as? UITextView {
if let limit = textView.limitLength {
if let _ = textView.markedTextRange {
//do nothing
return
}
if let text = textView.text {
if (text as NSString).length >= limit {
textView.text = (text as NSString).substringWithRange(NSMakeRange(0, limit))
}
}
}
if let placeholderLabel = textView.viewWithTag(100) {
if !textView.hasText() {
// Get the placeholder label
placeholderLabel.hidden = false
}
else {
placeholderLabel.hidden = true
}
}
}
}
}
上面的代码除了给UITextView添加了limitLength属性,还顺带添加了一个placeholder属性用于设置placeholder字符串。
我是咕咕鸡,一个还在不停学习的全栈工程师。
热爱生活,喜欢跑步,家庭是我不断向前进步的动力。