可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I know there are other topics on this but I can't seem to find out how to implement it.
I'm trying to limit a UITextField to only 5 Characters
Preferably Alphanumeric and - and . and _
I've seen this code
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
and
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = count(textField.text.utf16) + count(string.utf16) - range.length
return length <= 10
}
I just don't know how to actually implement it or which "textfield" should I swap out for my custom named UITextField
回答1:
Your view controller should conform to UITextFieldDelegate
, like below:
class MyViewController: UIViewController, UITextFieldDelegate {
}
Set the delegate of your textfield: myTextField.delegate = self
- Implement the method in your view controller :
textField(_:shouldChangeCharactersInRange:replacementString:)
All together:
class MyViewController: UIViewController,UITextFieldDelegate //set delegate to class
@IBOutlet var mytextField: UITextField // textfield variable
override func viewDidLoad() {
super.viewDidLoad()
mytextField.delegate = self //set delegate
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
For Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 1
let currentString: NSString = textField.text! as NSString
let newString: NSString =
currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
Allowing only a specified set of characters to be entered into a given text field
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var result = true
if mytextField == numberField {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
result = replacementStringIsLegal
}
}
return result
}
How to program an iOS text field that takes only numeric input with a maximum length
回答2:
Dec 2017. Swift 4.
Take care that much of the example code which you will see online regarding this problem is very out of date.
Paste the following into any Swift file in your project. You can name the file anything, for example, "Handy.swift"
This finally fixes one of the stupidest problems in iOS:
Your text fields now have a .maxLength
.
It is completely OK to set that value in storyboard during development, or, set it in code while the app is running.
// simply have this in any Swift file, say, Handy.swift
import UIKit
private var __maxLengths = [UITextField: Int]()
extension UITextField {
@IBInspectable var maxLength: Int {
get {
guard let l = __maxLengths[self] else {
return 150 // (global default-limit. or just, Int.max)
}
return l
}
set {
__maxLengths[self] = newValue
addTarget(self, action: #selector(fix), for: .editingChanged)
}
}
func fix(textField: UITextField) {
let t = textField.text
textField.text = t?.prefix(maxLength)
}
}
It's that simple.
Footnote - these days to safely truncate a String
in swift, you simply .prefix(n)
An even simpler one-off version...
The above fixes all text fields in your project.
If you just want one particular text field to simply be limited to say "4", and that's that...
class PinCodeEntry: UITextField {
override func didMoveToSuperview() {
super.didMoveToSuperview()
addTarget(self, action: #selector(fixMe), for: .editingChanged)
}
@objc private func fixMe() { text = text?.prefix(4) }
}
Phew! That's all there is to it.
(Just BTW, here's a similar very useful tip relating to UITextView,
https://stackoverflow.com/a/42333832/294884 )
回答3:
Swift 4, simply use:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < 10
}
回答4:
The same way Steven Schmatz did it but using Swift 3.0 :
//max Length
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
回答5:
I think extension is more handy for this. See full answer here
private var maxLengths = [UITextField: Int]()
// 2
extension UITextField {
// 3
@IBInspectable var maxLength: Int {
get {
// 4
guard let length = maxLengths[self] else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
// 5
addTarget(
self,
action: #selector(limitLength),
forControlEvents: UIControlEvents.EditingChanged
)
}
}
func limitLength(textField: UITextField) {
// 6
guard let prospectiveText = textField.text
where prospectiveText.characters.count > maxLength else {
return
}
let selection = selectedTextRange
// 7
text = prospectiveText.substringWithRange(
Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
)
selectedTextRange = selection
}
}
回答6:
Other solutions posted above produce a retain cycle due to the textfield map. Besides, the maxLength
property should be nullable if not set instead of artificial Int.max
constructions; and the target will be set multiple times if maxLength is changed.
Here an updated solution for Swift4 with a weak map to prevent memory leaks and the other fixes
private var maxLengths = NSMapTable<UITextField, NSNumber>(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)
extension UITextField {
var maxLength: Int? {
get {
return maxLengths.object(forKey: self)?.intValue
}
set {
removeTarget(self, action: #selector(limitLength), for: .editingChanged)
if let newValue = newValue {
maxLengths.setObject(NSNumber(value: newValue), forKey: self)
addTarget(self, action: #selector(limitLength), for: .editingChanged)
} else {
maxLengths.removeObject(forKey: self)
}
}
}
@IBInspectable var maxLengthInspectable: Int {
get {
return maxLength ?? Int.max
}
set {
maxLength = newValue
}
}
@objc private func limitLength(_ textField: UITextField) {
guard let maxLength = maxLength, let prospectiveText = textField.text, prospectiveText.count > maxLength else {
return
}
let selection = selectedTextRange
text = String(prospectiveText[..<prospectiveText.index(from: maxLength)])
selectedTextRange = selection
}
}
回答7:
Simple solution without using delegate:
TEXT_FIELD.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged)
@objc private func editingChanged(sender: UITextField) {
if let text = sender.text, text.count >= MAX_LENGHT {
sender.text = String(text.dropLast(text.count - MAX_LENGHT))
return
}
}
回答8:
My Swift 4 version of shouldChangeCharactersIn
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
guard let preText = textField.text as NSString?,
preText.replacingCharacters(in: range, with: string).count <= MAX_TEXT_LENGTH else {
return false
}
return true
}
回答9:
I have something to add to Aladin's answer:
Your view controller should conform to UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate {
}
Set the delegate of your textfield:
To set the delegate, you can control drag from the textfield to your view controller in the storyboard. I think this is preferable to setting it in code
Implement the method in your view controller : textField(_:shouldChangeCharactersInRange:replacementString:)
回答10:
I give a supplementary answer based on @Frouo. I think his answer is the most beautiful way. Becuase it's a common control we can reuse. And there is no leak problem here.
private var kAssociationKeyMaxLength: Int = 0
extension UITextField {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
return length
} else {
return Int.max
}
}
set {
objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
//The method is used to cancel the check when use Chinese Pinyin input method.
//Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
func isInputMethod() -> Bool {
if let positionRange = self.markedTextRange {
if let _ = self.position(from: positionRange.start, offset: 0) {
return true
}
}
return false
}
func checkMaxLength(textField: UITextField) {
guard !self.isInputMethod(), let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
text = prospectiveText.substring(to: maxCharIndex)
selectedTextRange = selection
}
}
回答11:
Working In Swift4
// STEP 1 set UITextFieldDelegate
class SignUPViewController: UIViewController , UITextFieldDelegate {
@IBOutlet weak var userMobileNoTextFiled: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// STEP 2 set delegate
userMobileNoTextFiled.delegate = self //set delegate
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// guard let text = userMobileNoTextFiled.text else { return true }
// let newLength = text.count + string.count - range.length
// return newLength <= 10
// }
// STEP 3 call func
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 10 // set your need
let currentString: NSString = textField.text! as NSString
let newString: NSString =
currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
}
回答12:
This answer is for Swift 4, and is pretty straight forward with the ability to let backspace through.
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
return textField.text!.count < 10 || string == ""
}
回答13:
update for this Fattie answer
thanks
extension UITextField {
/// Runtime key
private struct AssociatedKeys {
/// max lenght key
static var maxlength: UInt8 = 0
/// temp string key
static var tempString: UInt8 = 0
}
/// Limit the maximum input length of the textfiled
@IBInspectable var maxLength: Int {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
addTarget(self, action: #selector(handleEditingChanged(textField:)), for: .editingChanged)
}
}
/// temp string
private var tempString: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.tempString) as? String
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.tempString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/// When the text changes, process the amount of text in the input box so that its length is within the controllable range.
@objc private func handleEditingChanged(textField: UITextField) {
/// Special Processing for Chinese Input Method
guard markedTextRange == nil else { return }
if textField.text?.count == maxLength {
/// SET lastQualifiedString where text length == max lenght
tempString = textField.text
} else if textField.text?.count ?? 0 < maxLength {
/// clear lastQualifiedString when text lengeht > maxlength
tempString = nil
}
/// keep current text range in arcgives
let archivesEditRange: UITextRange?
if textField.text?.count ?? 0 > maxLength {
/// if text length > maxlength,remove last range,to move to -1 postion.
let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.endOfDocument
archivesEditRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position))
} else {
/// just set current select text range
archivesEditRange = selectedTextRange
}
/// main handle string max length
textField.text = tempString ?? String((textField.text ?? "").prefix(maxLength))
/// last config edit text range
textField.selectedTextRange = archivesEditRange
}
/// get safe textPosition
private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition {
/* beginningOfDocument -> The end of the the text document. */
return optionlTextPosition ?? endOfDocument
}
}
回答14:
Swift 5
Credit: http://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/
Just write one to set max char length
self.textField.maxLength = 10
For more detial click here
回答15:
TextField Limit Character After Block the Text in Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range:
NSRange,replacementString string: String) -> Bool
{
if textField == self.txtDescription {
let maxLength = 200
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
return true
}
回答16:
Just in case, don't forget to guard range size before applying it to the string.
Otherwise, you will get crash if the user will do this:
Type maximum length text
Insert something (Nothing will be inserted due to length limitation, but iOS doesn't know about it)
Undo insertion (You get crash, cause range will be greater than actual string size)
Also, using iOS 13 users can accidentally trigger this by gestures
I suggest you add to your project this
extension String {
func replace(with text: String, in range: NSRange) -> String? {
guard range.location + range.length <= self.count else { return nil }
return (self as NSString).replacingCharacters(in: range, with: text)
}
}
And use it like this:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard let newText = textView.text.replace(with: text, in: range) else { return false }
return newText.count < maxNumberOfCharacters
}
Otherwise, you will constantly be getting crashed in your app
回答17:
Here's a Swift 3.2+ alternative that avoids unnecessary string manipulation. In this case, the maximum length is 10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
return text.count - range.length + string.count <= 10
}
回答18:
I use this step, first Set delegate texfield in viewdidload.
override func viewDidLoad() {
super.viewDidLoad()
textfield.delegate = self
}
and then shouldChangeCharactersIn after you include UITextFieldDelegate.
extension viewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newLength = (textField.text?.utf16.count)! + string.utf16.count - range.length
if newLength <= 8 {
return true
} else {
return false
}
}
}
回答19:
Simply just check with the number of characters in the string
- Add a delegate to view controller ans asign delegate
class YorsClassName : UITextFieldDelegate {
}
- check the number of chars allowed for textfield
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text?.count == 1 {
return false
}
return true
}
Note: Here I checked for only char allowed in textField