2009-07-16 12 views
5

Il problema della limitazione stringhe inserito direttamente in un UITextView o UITextField è stato affrontato su SO prima:Limitazione lunghezza della stringa incollato UITextView o UITextField

Tuttavia ora con OS 3.0 copia-e-incolla diventa un problema, poiché le soluzioni nelle domande SO sopra non impediscono di incollare caratteri aggiuntivi (cioè non puoi digitare più di 10 caratteri in un campo che è configurato con h le soluzioni precedenti ma puoi incollare facilmente 100 caratteri nello stesso campo).

Esiste un mezzo per impedire l'immissione diretta della stringa e overflow della stringa incollata?

+0

possibile duplicato del [iPhone SDK: Impostare Lunghezza massima caratteri TextField] (http://stackoverflow.com/questions/433337/iphone-sdk-set-max-character-length-textfield) – JosephH

risposta

0

Una delle risposte nella prima domanda che legata soprattutto al dovrebbe funzionare, vale a dire usando qualcosa come

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

a guardare per modifiche al testo nel UITextField e accorciare quando appropriato.

+1

In questo caso particolare , conforme a UITextViewDelegate (o UITextFieldDelegate) è preferibile al rollare la tua notifica (e più facile da eseguire il debug). E probabilmente dovrei postare come ho effettivamente risolto questo problema ... –

10

Sono stato in grado di limitare il testo inserito e incollato conformandosi al metodo textViewDidChange: all'interno del protocollo UITextViewDelegate.

- (void)textViewDidChange:(UITextView *)textView 
{ 
    if (textView.text.length >= 10) 
    { 
     textView.text = [textView.text substringToIndex:10]; 
    } 
} 

Ma io continuo a considerare questo tipo di un brutto hack, e sembra Apple dovrebbe aver fornito una sorta di "maxLength" di proprietà di UITextFields e UITextViews.

Se qualcuno è a conoscenza di una soluzione migliore, si prega di dire.

+0

Questo provoca un arresto anomalo quando I 'Annulla'. Vedi la mia risposta per una soluzione "leggermente" migliore. –

7

Nella mia esperienza solo l'attuazione del metodo delegato:

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

opere con incollare. L'intera stringa incollata si trova nell'argomento replacementString :. Basta controllare la sua lunghezza e, se è più lunga della lunghezza massima, restituire NO da questo metodo delegato. Questo non fa sì che nulla venga incollato. In alternativa, è possibile eseguire la sottostringa come nella precedente risposta suggerita, ma ciò consente di evitare l'incolla se è troppo lungo, se è ciò che si desidera.

+0

Non incollare se il testo è troppo lungo non è l'ideale –

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

    if(string.length>10){ 
    return NO; 
    } 
    return YES; 
} 
+2

Questo non funziona! – fengd

5

Cambiare il testo dopo che è stato inserito in textViewDidChange: causa l'arresto anomalo dell'app se l'utente preme "Annulla" dopo l'incolla.

Ho giocato un po 'e sono riuscito a trovare una soluzione funzionante. Fondamentalmente la logica è, non permettere l'incolla se la lunghezza totale è maggiore dei caratteri massimi, rilevare la quantità che è traboccata e inserire solo la stringa parziale.

Utilizzando questa soluzione il vostro pasteboard e undo manager funzioneranno come previsto.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { 
    NSInteger newLength = textView.text.length - range.length + text.length; 

    if (newLength > MAX_LENGTH) { 
     NSInteger overflow = newLength - MAX_LENGTH; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      UITextPosition *start = [textView positionFromPosition:nil offset:range.location]; 
      UITextPosition *end = [textView positionFromPosition:nil offset:NSMaxRange(range)]; 
      UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end]; 
      [textView replaceRange:textRange withText:[text substringToIndex:text.length - overflow]]; 
     }); 
     return NO; 
    } 
    return YES; 
} 
+0

Questo può essere fatto senza il dispatch_async. dispatch_async causerà un arresto anomalo su iOS8 con la nuova funzionalità type ahead. Riprenderò presto il codice. –

0

Inoltre, la lunghezza della stringa come in '[lunghezza stringa]' è una cosa, ma spesso si ha la necessità di interrompere a un conteggio di byte in una certa codifica. Avevo bisogno di troncare digitando e incollando in un UITextView fino a un massimo di UTF8, ecco come l'ho fatto. (Fare qualcosa di simile per UITextField è un esercizio per il lettore.)

NSString + TruncateUTF8.h

#import <Foundation/Foundation.h> 
@interface NSString (TruncateUTF8) 
- (NSString *)stringTruncatedToMaxUTF8ByteCount:(NSUInteger)maxCount; 
@end 

NSString + TruncateUTF8.m

#import "NSString+TruncateUTF8.h" 
@implementation NSString (TruncateUTF8) 
- (NSString *)stringTruncatedToMaxUTF8ByteCount:(NSUInteger)maxCount { 
    NSRange truncatedRange = (NSRange){0, MIN(maxCount, self.length)}; 
    NSInteger byteCount; 

    // subtract from this range to account for the difference between NSString's 
    // length and the string byte count in utf8 encoding 
    do { 
    NSString *truncatedText = [self substringWithRange:truncatedRange]; 
    byteCount = [truncatedText lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 
    if (byteCount > maxCount) { 
     // what do we subtract from the length to account for this excess count? 
     // not the count itself, because the length isn't in bytes but utf16 units 
     // one of which might correspond to 4 utf8 bytes (i think) 
     NSUInteger excess = byteCount - maxCount; 
     truncatedRange.length -= ceil(excess/4.0); 
     continue; 
    } 
    } while (byteCount > maxCount); 

    // subtract more from this range so it ends at a grapheme cluster boundary 
    for (; truncatedRange.length > 0; truncatedRange.length -= 1) { 
    NSRange revisedRange = [self rangeOfComposedCharacterSequencesForRange:truncatedRange]; 
    if (revisedRange.length == truncatedRange.length) 
     break; 
    } 

    return (truncatedRange.length < self.length) ? [self substringWithRange:truncatedRange] : self; 
} 
@end 

// tested using: 
// NSString *utf8TestString = @"Hello world, Καλημέρα κόσμε, コンニチハ ∀x∈ℝ ıntəˈnæʃənəl ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ STARGΛ̊TE γνωρίζω გთხოვთ Зарегистрируйтесь ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช ሰማይ አይታረስ ንጉሥ አይከሰስ። ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ ░░▒▒▓▓██ ▁▂▃▄▅▆▇█"; 
// NSString *truncatedString; 
// NSUInteger byteCount = [utf8TestString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 
// NSLog(@"length %d: %p %@", (int)byteCount, utf8TestString, utf8TestString); 
// for (; byteCount > 0; --byteCount) { 
//  truncatedString = [utf8TestString stringTruncatedToMaxUTF8ByteCount:byteCount]; 
//  NSLog(@"truncate to length %d: %p %@ (%d)", (int)byteCount, truncatedString, truncatedString, (int)[truncatedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); 
// } 

MyViewController.m

#import "NSString+TruncateUTF8.h" 
... 
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)replacementText 
{ 
    NSMutableString *newText = textView.text.mutableCopy; 
    [newText replaceCharactersInRange:range withString:replacementText]; 

    // if making string larger then potentially reject 
    NSUInteger replacementTextLength = replacementText.length; 
    if (self.maxByteCount > 0 && replacementTextLength > range.length) { 
    // reject if too long and adding just 1 character 
    if (replacementTextLength == 1 && [newText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > self.maxByteCount) { 
     return NO; 
    } 

    // if adding multiple charaters, ie. pasting, don't reject altogether but instead return YES 
    // to accept and truncate immediately after, see http://stackoverflow.com/a/23155325/592739 
    if (replacementTextLength > 1) { 
     NSString *truncatedText = [newText stringTruncatedToMaxUTF8ByteCount:self.maxByteCount]; // returns same string if truncation needed 
     if (truncatedText != newText) { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0LL), dispatch_get_main_queue(), ^{ 
      UITextPosition *replaceStart = [textView positionFromPosition:textView.beginningOfDocument offset:range.location]; 
      UITextRange *textRange = [textView textRangeFromPosition:replaceStart toPosition:textView.endOfDocument]; 
      [textView replaceRange:textRange withText:[truncatedText substringFromIndex:range.location]]; 

      self.rowDescriptor.value = (truncatedText.length > 0) ? truncatedText : nil; 
     }); 
     } 
    } 
    } 

    [self updatedFieldWithString:(newText.length > 0) ? newText : nil]; // my method 
    return YES; 
} 
+0

grazie amico! questo frammento mi ha aiutato a capire il modo corretto di sostituire il testo in un campo di testo! Ho creato una versione 3 rapida: https://gist.github.com/Blackjacx/2198d86442ec9b9b05c0801f4e392047 – blackjacx

0

è possibile conoscere la stringa incollato se controlli per string.length in shouldChangeCharactersIn range: metodo delegato

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 
    if string.length > 1 { 
     //pasted string 
     // do you stuff like trim 
    } else { 
     //typed string 
    } 
    return true 
} 
Problemi correlati