ตั้งค่าความยาวอักขระสูงสุดของ UITextField


474

ฉันจะตั้งค่าจำนวนตัวอักษรสูงสุดใน a UITextFieldบน SDK ของ iPhone ได้อย่างไรเมื่อฉันโหลด a UIView?


คำตอบเก่าอย่างไม่น่าเชื่อนี้ล้าสมัยแล้ว - คำตอบอยู่เล็กน้อย: stackoverflow.com/a/38306929/294884
Fattie

สำเนาซ้ำที่เป็นไปได้ของการตั้งค่าความยาวอักขระสูงสุดของ UITextField ใน Swift
Fattie

คำตอบ:


1029

ในขณะที่UITextFieldคลาสนั้นไม่มีคุณสมบัติความยาวสูงสุดมันค่อนข้างง่ายที่จะได้รับฟังก์ชั่นนี้โดยการตั้งค่าฟิลด์ข้อความdelegateและการใช้วิธีการมอบหมายต่อไปนี้:

Objective-C

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // Prevent crashing undo bug – see note below.
    if(range.length + range.location > textField.text.length)
    {
        return NO;
    }

    NSUInteger newLength = [textField.text length] + [string length] - range.length;
    return newLength <= 25;
}

รวดเร็ว

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let currentCharacterCount = textField.text?.count ?? 0
    if range.length + range.location > currentCharacterCount {
        return false
    }
    let newLength = currentCharacterCount + string.count - range.length
    return newLength <= 25
}

ก่อนที่ฟิลด์ข้อความจะเปลี่ยนแปลง UITextField จะถามผู้ร่วมประชุมว่าควรเปลี่ยนข้อความที่ระบุหรือไม่ ช่องข้อความยังไม่เปลี่ยนแปลง ณ จุดนี้ดังนั้นเราจึงคว้าความยาวปัจจุบันและความยาวสตริงที่เรากำลังแทรก (ไม่ว่าจะเป็นการวางข้อความที่คัดลอกหรือพิมพ์อักขระเดียวโดยใช้แป้นพิมพ์) ลบความยาวของช่วง หากค่านี้ยาวเกินไป (มากกว่า 25 อักขระในตัวอย่างนี้) ให้ส่งคืนNOไปเพื่อห้ามการเปลี่ยนแปลง

เมื่อพิมพ์อักขระเดียวที่ท้ายฟิลด์ข้อความrange.locationความยาวของฟิลด์ปัจจุบันrange.lengthจะเป็น 0 และจะเป็น 0 เพราะเราไม่ได้แทนที่ / ลบอะไรเลย การแทรกลงในกึ่งกลางของฟิลด์ข้อความหมายถึงสิ่งที่แตกต่างrange.locationและการวางอักขระหลายตัวก็หมายถึงstringมีอักขระมากกว่าหนึ่งตัว

การลบอักขระเดียวหรือการตัดหลายอักขระถูกระบุโดย rangeมีความยาวไม่เป็นศูนย์และสตริงว่าง การแทนที่เป็นเพียงการลบช่วงด้วยสตริงที่ไม่ว่างเปล่า

หมายเหตุเกี่ยวกับข้อผิดพลาด "เลิกทำ" ข้อผิดพลาด

ตามที่ระบุไว้ในความคิดเห็นมีข้อผิดพลาดUITextFieldที่สามารถนำไปสู่ความผิดพลาด

หากคุณวางในฟิลด์ แต่การวางถูกป้องกันโดยการใช้งานการตรวจสอบความถูกต้องของคุณการดำเนินการวางจะยังคงถูกบันทึกในบัฟเฟอร์การเลิกทำของแอปพลิเคชัน หากคุณเปิดใช้เลิกทำ (โดยเขย่าอุปกรณ์และยืนยันการเลิกทำ) UITextFieldจะพยายามแทนที่สตริงที่คิดว่าวางไว้ในตัวเองด้วยสตริงว่าง นี้จะผิดพลาดเพราะมันไม่จริงวางสตริงในตัวเอง มันจะพยายามแทนที่ส่วนของสตริงที่ไม่มีอยู่

โชคดีที่คุณสามารถป้องกันการUITextFieldฆ่าตัวตายเช่นนี้ คุณเพียงแค่ต้องแน่ใจว่าช่วงที่เสนอให้แทนที่นั้นมีอยู่ในสตริงปัจจุบัน นี่คือสิ่งที่การตรวจสุขภาพจิตเบื้องต้นด้านบนทำ

swift 3.0 พร้อมการคัดลอกและวางทำงานได้ดี

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

หวังว่ามันจะเป็นประโยชน์กับคุณ


7
พบวิธีแก้ปัญหาโดยล้อมรอบทั้งสองบรรทัดด้วย if (textField == _ssn) {} และเพิ่ม YES ผลตอบแทน; ในตอนท้ายของวิธีการซึ่งจะทำให้ UITextFields อื่น ๆ ทั้งหมดยอมรับข้อความโดยไม่มีข้อ จำกัด Nifty!
Kyle Clegg

55
คำตอบที่ดี แต่ผู้ประกอบการที่สามคือฟุ่มเฟือย; คุณสามารถใส่return newLength <= 25;
jowie

2
ถ้าคุณแค่ต้องการให้ข้อความไม่กระจายไปตามเฟรมของฟิลด์ข้อความ อักขระทุกตัวมีความกว้างเท่ากันใช่ไหม
Morkrom

2
มีข้อผิดพลาดในการเลิกทำอย่างที่ @bcherry กล่าวถึง - ทดสอบกับUITextFieldiPad iOS 8.1 (+1 เพื่อแสดงความคิดเห็น) ผู้เขียนจะเพิ่มบางสิ่งบางอย่างเกี่ยวกับสิ่งนี้หรือไม่ ฉันยินดีที่จะแก้ไข แต่ฉันเป็นประจำดูเหมือนจะถูกปฏิเสธ! :-)
Benjohn

8
@bherry In Swift การตรวจสอบกรณีการเลิกทำดูเหมือนจะทำลายการเข้าสู่อิโมจิ ไม่ควรนับจำนวนจริง (textField.text) (textField.text.utf16) เพื่อให้ตรงกับการรายงาน objc / uikit ในช่วง (เทียบกับความแปรปรวนของการนับบนสตริง) ของ Swift
rcw3

62

สวิฟท์ 4

import UIKit

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)
            addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }

    @objc func checkMaxLength(textField: UITextField) {
        guard let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange

        let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        let substring = prospectiveText[..<indexEndOfText]
        text = String(substring)

        selectedTextRange = selection
    }
}

แก้ไข: ปัญหาการรั่วไหลของหน่วยความจำได้รับการแก้ไข

ป้อนคำอธิบายรูปภาพที่นี่


ความคิดที่ดี Frouo! ฉันขยายมันในคำตอบของฉันเพื่อย้าย maxLength trimming ไปยังส่วนขยายของสตริงเพื่อให้สามารถใช้สำหรับสิ่งต่าง ๆ เช่นอินสแตนซ์ UITextView และเพื่อเพิ่มฟังก์ชั่นอำนวยความสะดวกเพื่อใช้ประโยชน์จากส่วนขยายสตริงเหล่านี้ในส่วนขยาย UITextField
Scott Gardner

1
ไม่ตัวแปรส่วนกลางนี้สร้างการรั่วไหลของหน่วยความจำโดยถือการอ้างอิงถึง textviews ทั้งหมด (ซึ่งอ้างอิงการดูแลจนถึงราก)
Ixx

3
@Ixx ฉันได้แก้ไขเพื่อแก้ไขปัญหาการรั่วไหลของหน่วยความจำที่คุณชี้ให้เห็น + รวดเร็ว 3. ขอบคุณ
frouo

1
วิธีที่สวยที่สุดที่จะทำให้สำเร็จ! ขอบคุณ
Victor Choy

ใครสามารถให้รุ่นวัตถุประสงค์ของฉัน
MRizwan33

56

ขอบคุณมาก! ( โพสต์ )

นี่คือรหัสที่ฉันใช้ด้วย:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField.text.length >= MAX_LENGTH && range.length == 0)
    {
        return NO; // return NO to not change text
    }
    else
    {return YES;}
}

19
น่าเสียดายที่โซลูชันนี้ไม่สามารถหยุดผู้ใช้คัดลอกและวางลงในฟิลด์ข้อความดังนั้นจึงอนุญาตให้ผู้ใช้ข้ามขีด จำกัด คำตอบของ Sickpea ตอบสนองกับสถานการณ์นี้อย่างถูกต้อง
Ant

5
ผู้ที่มีคำสั่ง if จะส่งคืน NO หรือ YES คืออะไร ลองนี้: return! (textField.text.length> = MAX_LENGTH && range.length == 0);
Matt Parkins

หรือนี่return textField.text.length < MAX_LENGTH || range.length != 0;
igrek

22

เพื่อให้คำตอบในเดือนสิงหาคมเสร็จสมบูรณ์การใช้งานที่เป็นไปได้ของฟังก์ชันที่เสนอ (ดูผู้แทนของ UITextField )

ผมไม่ได้ทดสอบdomnessรหัส แต่เหมืองไม่ได้รับการติดหากผู้ใช้ถึงขีด จำกัด และมันเข้ากันได้กับสตริงใหม่ที่มาแทนที่ที่มีขนาดเล็กหรือเท่ากับหนึ่ง

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //limit the size :
    int limit = 20;
    return !([textField.text length]>limit && [string length] > range.length);
}

17

คุณไม่สามารถทำสิ่งนี้โดยตรง - UITextFieldไม่มีแอ็ตทริบิวต์maxLengthแต่คุณสามารถตั้งค่าUITextField'sผู้รับมอบสิทธิ์จากนั้นใช้:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

5
ฉันเห็นด้วยนี่เป็นวิธีที่ดีที่สุดไปข้างหน้า แต่มันยังคงแฮ็กอยู่เล็กน้อย ส่งรายงานข้อผิดพลาดไปยัง Apple ที่คุณต้องการดูคุณสมบัติสำหรับความยาวข้อความ ฉันสนใจสิ่งนี้เช่นกัน
avocade

5
@avocade ไม่ใช่แฮ็ค: เป็นตัวอย่างที่คุณต้องทำเฟรมเวิร์กโค้ดพื้นฐานที่ Apple ควรทำเพื่อคุณ มีตัวอย่างมากมายใน iOS SDK
Dan Rosenstark

13

บ่อยครั้งที่คุณมีช่องป้อนข้อมูลหลายช่องที่มีความยาวแตกต่างกัน

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    int allowedLength;
    switch(textField.tag) {
        case 1: 
            allowedLength = MAXLENGTHNAME;      // triggered for input fields with tag = 1
            break;
        case 2:
            allowedLength = MAXLENGTHADDRESS;   // triggered for input fields with tag = 2
            break;
        default:
            allowedLength = MAXLENGTHDEFAULT;   // length default when no tag (=0) value =255
            break;
    }

    if (textField.text.length >= allowedLength && range.length == 0) {
        return NO; // Change not allowed
    } else {
        return YES; // Change allowed
    }
}

12

วิธีที่ดีที่สุดคือการตั้งค่าการแจ้งเตือนเมื่อมีการเปลี่ยนแปลงข้อความ ใน-awakeFromNibวิธีการควบคุมมุมมองของคุณคุณจะต้อง:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];

จากนั้นในชั้นเรียนเดียวกันเพิ่ม:

- (void)limitTextField:(NSNotification *)note {
    int limit = 20;
    if ([[myTextField stringValue] length] > limit) {
        [myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
    }
}

จากนั้นเชื่อมต่อกับเต้าเสียบmyTextFieldของคุณUITextFieldและมันจะไม่อนุญาตให้คุณเพิ่มตัวละครอีกต่อไปหลังจากที่คุณถึงขีด จำกัด โปรดเพิ่มสิ่งนี้ลงในวิธีการจัดสรรคืนเงินของคุณ:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];

แม้ว่าฉันทำสิ่งนี้เพื่อลบข้อผิดพลาด> myTextField.text = [myTextField.text substringToIndex: จำกัด ];
ลุค

11

ฉันสร้างคลาสย่อย UITextFieldLimit นี้ :

  • รองรับหลาย Text Text
  • ตั้งค่าขีดจำกัดความยาวของข้อความ
  • การป้องกันการวาง
  • แสดงเลเบลของอักขระทางซ้ายภายในฟิลด์ข้อความซ่อนเมื่อคุณหยุดแก้ไข
  • เขย่าภาพเคลื่อนไหวเมื่อไม่มีตัวอักษรเหลืออยู่

หยิบUITextFieldLimit.hและUITextFieldLimit.mจากที่เก็บ GitHub นี้:

https://github.com/JonathanGurebo/UITextFieldLimit

และเริ่มทดสอบ!

ทำเครื่องหมาย UITextField ที่สร้างจากกระดานเรื่องราวของคุณและเชื่อมโยงไปยังคลาสย่อยของฉันโดยใช้ Identity Inspector:

สารวัตรประจำตัว

จากนั้นคุณสามารถลิงก์ไปยัง IBOutlet และตั้งค่าขีด จำกัด (ค่าเริ่มต้นคือ 10)


ไฟล์ ViewController.h ของคุณควรมี: (หากคุณไม่ต้องการแก้ไขการตั้งค่าเช่นขีด จำกัด )

#import "UITextFieldLimit.h"

/.../

@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet

ไฟล์ ViewController.m @synthesize textFieldLimitของคุณควร


ตั้งค่าขีดจำกัดความยาวข้อความในไฟล์ ViewController.m ของคุณ:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    [textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}

หวังว่าชั้นเรียนจะช่วยคุณ โชคดี!


สำหรับความต้องการตัวละครที่ จำกัด ฉันคิดว่าการเพิ่มชั้นเรียนของคุณจะเกินความจำเป็น
Domness

ยังคงชื่นชมความพยายาม
เรียบเรียง

11

นี่น่าจะเพียงพอสำหรับการแก้ปัญหา (แทนที่ 4 ด้วยขีด จำกัด u ที่ต้องการ) ตรวจสอบให้แน่ใจว่าได้เพิ่มผู้รับมอบสิทธิ์ใน IB

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
     return (newString.length<=4);
}

9

การใช้งานด้านล่างขยายไปตั้งค่าความยาวตัวอักษรสูงสุดและUITextFieldUITextView

Swift 4.0

    private var kAssociationKeyMaxLength: Int = 0
    private var kAssociationKeyMaxLengthTextView: 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)
                addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
            }
        }

        @objc func checkMaxLength(textField: UITextField) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

UITextView

extension UITextView:UITextViewDelegate {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                self.delegate = self

                objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
            }
        }

        public func textViewDidChange(_ textView: UITextView) {
            checkMaxLength(textField: self)
        }
        @objc func checkMaxLength(textField: UITextView) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

คุณสามารถตั้งค่าขีด จำกัด ด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่


คำตอบที่ดีที่สุดโดยไกล ,, ขอบคุณมากทางออกที่ดีเมื่อมีหลาย textfields ที่ต้องการความยาวแตกต่างกัน
Carlos Norena

ทางออกที่ดีมากสำหรับฟิลด์ข้อความและการ จำกัด จำนวนอักขระควบคุมของ textview บันทึกรหัสและเวลาสำหรับนักพัฒนา ... :)
Sandip Patel - SM

วิธีนี้ใช้ได้ดีกว่าโซลูชันอื่น ๆ ที่ฉันพบ ตัวอย่างเช่นหากคุณมีอิโมจิในฟิลด์ข้อความของคุณส่วนขยายอื่น ๆ ที่ฉันพบจะข้ามไปที่ท้ายบรรทัดเมื่อทำการแก้ไข แต่รหัสของคุณไม่ได้ทำอย่างนั้น ขอบคุณ!
Phontaine Judd

7

ฉันจำลองการแทนที่สตริงจริงที่จะเกิดขึ้นเพื่อคำนวณความยาวของสตริงในอนาคต:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if([newString length] > maxLength)
       return NO;

    return YES;
}

7

Swift 3 version // ***** นี่จะไม่ทำงานกับ Swift 2.x! ***** //

ขั้นแรกให้สร้างไฟล์ Swift ใหม่: TextFieldMaxLength.swift จากนั้นเพิ่มรหัสด้านล่าง:

import UIKit

private var maxLengths = [UITextField: Int]()

extension UITextField {

   @IBInspectable var maxLength: Int {

      get {

          guard let length = maxLengths[self] 
             else {
                return Int.max
      }
      return length
   }
   set {
      maxLengths[self] = newValue
      addTarget(
         self,
         action: #selector(limitLength),
         for: UIControlEvents.editingChanged
      )
   }
}
func limitLength(textField: UITextField) {
    guard let prospectiveText = textField.text,
        prospectiveText.characters.count > maxLength
    else {
        return
    }

   let selection = selectedTextRange
   let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
   text = prospectiveText.substring(to: maxCharIndex)
   selectedTextRange = selection
   }
}

จากนั้นคุณจะเห็นฟิลด์ใหม่ (ความยาวสูงสุด) ในกระดานเรื่องราวเมื่อคุณเลือกฟิลด์ข้อความใด ๆ

หากคุณยังมีคำถามเพิ่มเติมลองดูที่ลิงค์นี้: http://www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields.html เข้าพักได้สูงสุดยาวภาพสตูดิโอสไตล์ /


คำเตือนตัวแปรโกลบอลนี้สร้างการรั่วไหลของหน่วยความจำโดยถือการอ้างอิงถึง textviews ทั้งหมด
frouo

6

การใช้เครื่องมือสร้างอินเทอร์เฟซคุณสามารถเชื่อมโยงและรับเหตุการณ์สำหรับ "แก้ไขการเปลี่ยนแปลง" ในฟังก์ชั่นของคุณ ตอนนี้คุณสามารถตรวจสอบความยาวได้แล้ว

- (IBAction)onValueChange:(id)sender 
{
    NSString *text = nil;
    int MAX_LENGTH = 20;
    switch ([sender tag] ) 
    {
        case 1: 
        {
            text = myEditField.text;
            if (MAX_LENGTH < [text length]) {
                myEditField.text = [text substringToIndex:MAX_LENGTH];
            }
        }
            break;
        default:
            break;
    }

}

6

รหัสต่อไปนี้คล้ายกับคำตอบของ sickp แต่จัดการการคัดลอกวางอย่างถูกต้อง หากคุณพยายามวางข้อความที่ยาวเกินขีด จำกัด รหัสต่อไปนี้จะตัดทอนข้อความให้พอดีกับขีด จำกัด แทนที่จะปฏิเสธการวางอย่างสมบูรณ์

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    static const NSUInteger limit = 70; // we limit to 70 characters
    NSUInteger allowedLength = limit - [textField.text length] + range.length;
    if (string.length > allowedLength) {
        if (string.length > 1) {
            // get at least the part of the new string that fits
            NSString *limitedString = [string substringToIndex:allowedLength];
            NSMutableString *newString = [textField.text mutableCopy];
            [newString replaceCharactersInRange:range withString:limitedString];
            textField.text = newString;
        }
        return NO;
    } else {
        return YES;
    }
}

6

มีวิธีแก้ไขปัญหาทั่วไปสำหรับการตั้งค่าความยาวสูงสุดใน Swift โดย IBInspectable คุณสามารถเพิ่มแอททริบิวใหม่ใน Xcode Attribute Inspectorป้อนคำอธิบายรูปภาพที่นี่

import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            guard let length = maxLengths[self]
            else {
                return Int.max
            }
            return length
        }
        set {
            maxLengths[self] = newValue
            addTarget(
                self,
                action: Selector("limitLength:"),
                forControlEvents: UIControlEvents.EditingChanged
            )
        }
    }

    func limitLength(textField: UITextField) {
        guard let prospectiveText = textField.text
            where prospectiveText.characters.count > maxLength else {
                return
        }
        let selection = selectedTextRange
        text = prospectiveText.substringWithRange(
            Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
        )
        selectedTextRange = selection
    }

}

ทางออกที่สะอาดและสมบูรณ์แบบ
Eduardo

การถือ UITextField ในเขตข้อมูลส่วนกลางจะเก็บไว้ในหน่วยความจำแม้หลังจากที่ยกเลิก UIViewController แล้ว นี่คือหน่วยความจำรั่ว อย่าใช้วิธีนี้
Gunhan

5

เพื่อให้มันทำงานกับ cut & paste ของสายยาว ๆ ผมแนะนำให้เปลี่ยนฟังก์ชั่นเป็น:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        NSInteger insertDelta = string.length - range.length;

        if (textField.text.length + insertDelta > MAX_LENGTH)
        {
           return NO; // the new string would be longer than MAX_LENGTH
        }
        else {
            return YES;
        }
    }

4

สวิฟท์ 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }
    let newLength = text.count + string.count - range.length
    return newLength <= 10
}

ทำไมguard?
oddRaven

ตรวจสอบว่าข้อความเป็นศูนย์ถ้าคุณต้องการคุณสามารถใช้ถ้า @oddRaven
Shan Ye

3

Swift 2.0 +

ก่อนอื่นให้สร้างคลาสสำหรับกระบวนการนี้ ให้เรียกมันว่า StringValidator.swift

จากนั้นเพียงวางรหัสต่อไปนี้ไว้ข้างใน

import Foundation

extension String {

func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}

func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}


func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}

func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()

return scanner.scanDecimal(nil) && scanner.atEnd
}

}

ตอนนี้บันทึกชั้นเรียน .....

การใช้งาน ..

ทีนี้กลับไปที่คลาส viewController.swift ของคุณแล้วทำให้ร้านของ textfield ของคุณเป็น ..

@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField!   //Second textfield

ตอนนี้กลับไปที่ textChangeChangeersInRange ของ textfield และใช้วิธีต่อไปนี้

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string.characters.count == 0 {
        return true
    }
    let latestText = textField.text ?? ""
    let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)


    switch textField {

    case contactEntryTxtFld:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    case contactEntryTxtFld2:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    default:
        return true
    }

}

อย่าลืมตั้งค่าโปรโตคอลผู้รับมอบสิทธิ์ / วิธีการของฟิลด์ข้อความ

ให้ฉันอธิบายเกี่ยวกับเรื่องนี้ ... ฉันใช้กระบวนการขยายสายอย่างง่ายซึ่งฉันเขียนไว้ในคลาสอื่น ตอนนี้ฉันแค่เรียกวิธีการขยายเหล่านั้นจากคลาสอื่นที่ฉันต้องการโดยเพิ่มการตรวจสอบและค่าสูงสุด

คุณสมบัติ ...

  1. มันจะตั้งค่าขีด จำกัด สูงสุดของฟิลด์ข้อความเฉพาะ
  2. มันจะตั้งค่าประเภทของคีย์ที่ยอมรับสำหรับฟิลด์ข้อความเฉพาะ

ประเภท ...

containOnlyCharactersIn // ยอมรับเฉพาะอักขระเท่านั้น

containCharactersIn // ยอมรับการรวมกันของตัวละคร

doesNotContainsCharactersIn // จะไม่ยอมรับอักขระ

หวังว่าจะช่วยได้ .... ขอบคุณ ..


3

สวิฟท์ 3.0

รหัสนี้ใช้งานได้ดีเมื่อคุณวางสตริงมากกว่าจำนวนอักขระสูงสุด

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

ขอบคุณสำหรับคะแนนโหวต :)


2
UITextField ไม่ใช่ UITextView
Jonny

3

ฉันให้คำตอบเพิ่มเติมตาม @Frouo ฉันคิดว่าคำตอบของเขาเป็นวิธีที่สวยที่สุด เพราะมันคือการควบคุมทั่วไปที่เราสามารถนำมาใช้ซ้ำได้

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)
        }
    }

    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
    }

    //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
    }

}

2

นี่เป็นวิธีที่ถูกต้องในการจัดการความยาวสูงสุดบน UITextField ซึ่งอนุญาตให้ปุ่มย้อนกลับออกจากการลาออกจากฟิลด์ข้อความเป็นผู้ตอบกลับครั้งแรกและให้ผู้ใช้ย้อนกลับเมื่อถึงขีด จำกัด

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
    if([string isEqualToString:@"\n"])
    {
        [textField resignFirstResponder];
        return FALSE;
    }
    else if(textField.text.length > MAX_LENGHT-1)
    {
        if([string isEqualToString:@""] && range.length == 1)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        return TRUE;
    }
}

2

สิ่งที่เกี่ยวกับวิธีการที่เรียบง่ายนี้ มันใช้งานได้ดีสำหรับฉัน

extension UITextField {

    func  charactersLimit(to:Int) {

        if (self.text!.count > to) {
            self.deleteBackward()
        }
    }
}

แล้ว:

someTextField.charactersLimit(to:16)

1

คำตอบอื่น ๆ ไม่จัดการกรณีที่ผู้ใช้สามารถวางสายยาวจากคลิปบอร์ด ถ้าฉันวางสายยาวมันควรจะถูกตัดทอน แต่แสดงให้เห็น ใช้สิ่งนี้ในตัวแทนของคุณ:

static const NSUInteger maxNoOfCharacters = 5;

-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;

if(text.length > maxNoOfCharacters)
{
    text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
    textField.text = text;
}

// use 'text'

}

1

รับโค้ดได้ 1 บรรทัด :)

ตั้งผู้รับมอบสิทธิ์ของมุมมองข้อความของคุณเป็น "ตัวเอง" แล้วเพิ่ม<UITextViewDelegate>ใน. h ของคุณและรหัสต่อไปนี้ใน. m ... ของคุณคุณสามารถปรับจำนวน "7" ให้เป็นสิ่งที่คุณต้องการจำนวนอักขระสูงสุดของคุณ

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}

รหัสนี้ใช้สำหรับการพิมพ์อักขระใหม่การลบอักขระการเลือกอักขระจากนั้นพิมพ์หรือลบการเลือกอักขระและการตัดการวางโดยทั่วไปและการเลือกอักขระและการวาง

ทำ!






อีกวิธีหนึ่งที่ยอดเยี่ยมในการเขียนรหัสนี้ด้วยการทำงานแบบบิตนั้นก็คือ

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}

1

ฉันเปิดซอร์สคลาสย่อย UITextField, STATextFieldซึ่งมีฟังก์ชันการทำงานนี้ (และอื่น ๆ อีกมากมาย) พร้อมmaxCharacterLengthคุณสมบัติ


1

ตอนนี้คุณต้องการให้ค่าอักขระกี่ตัว

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range   replacementString:(NSString *)string {
     NSUInteger newLength = [textField.text length] + [string length] - range.length;
     return (newLength > 25) ? NO : YES;
  }

1

ใช้รหัสนี้ที่นี่ RESTRICTED_LENGTH คือความยาวที่คุณต้องการ จำกัด สำหรับฟิลด์ข้อความ

   - (BOOL)textField:(UITextField *)textField     shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == nameTF) {
    int limit = RESTRICTED_LENGTH - 1;
    return !([textField.text length]>limit && [string length] > range.length);
    }
   else
   {
    return YES;
   }

return NO;

}

1

ฉันทำสิ่งนี้ใน Swift ไม่เกิน 8 ตัวอักษรเมื่อใช้แป้นตัวเลข

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}

ฉันต้องทดสอบสตริง! = "" เพื่อให้ปุ่มลบทำงานบนแป้นตัวเลขมิฉะนั้นจะไม่อนุญาตให้ลบอักขระในช่องข้อความหลังจากถึงขีดสูงสุดแล้ว


1

สำหรับ Xamarin:

YourTextField.ShouldChangeCharacters = 
delegate(UITextField textField, NSRange range, string replacementString)
        {
            return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
        };

1

ฉันใช้ส่วนขยาย UITextField เพื่อเพิ่มคุณสมบัติ maxLength ให้กับมัน

มันขึ้นอยู่กับ Xcode 6 IBInspectables ดังนั้นคุณสามารถตั้งค่าขีด จำกัด สูงสุดของความยาวบนเครื่องมือสร้างส่วนต่อประสาน

นี่คือการดำเนินการ:

UITextField + MaxLength.h

#import <UIKit/UIKit.h>

@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>

@property (nonatomic)IBInspectable int textMaxLength;
@end

UITextField + MaxLength.m

#import "UITextField+MaxLength.h"

@interface UITextField_MaxLength()

@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;

@end

@implementation UITextField_MaxLength

- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    //validate the length, only if it's set to a non zero value
    if (self.textMaxLength>0) {
        if(range.length + range.location > textField.text.length)
            return NO;

        if (textField.text.length+string.length - range.length>self.textMaxLength) {
            return NO;
        }
    }

    //if length validation was passed, query the super class to see if the delegate method is implemented there
    if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    else{
        //if the super class does not implement the delegate method, simply return YES as the length validation was passed
        return YES;
    }
}

- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
    if (delegate == self)
        return;
    self.superDelegate = delegate;
    [super setDelegate:self];
}

//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.superDelegate  respondsToSelector:aSelector])
        return self.superDelegate;

    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([self.superDelegate respondsToSelector:aSelector])
        return YES;

    return [super respondsToSelector:aSelector];
}
@end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.