2009-07-16 49 views
5

被直接輸入到一個UITextView或的UITextField已上之前SO被尋址限制串的問題粘貼字符串長度:限制在的UITextView或的UITextField

然而現在OS 3.0複製粘貼成爲一個問題,因爲上述SO問題中的解決方案不會阻止粘貼其他字符(即,您不能在配置的字段中鍵入超過10個字符h上述解決方案,但您可以輕鬆地將100個字符粘貼到相同的字段中)。

是否有防止直接輸入字符串粘貼字符串溢出的手段?

+0

[iPhone SDK:設置最大字符長度的TextField]的可能重複(http://stackoverflow.com/questions/433337/iphone-sdk-set-max-character-length-textfield) – JosephH 2012-03-05 11:00:51

回答

0

一個你上面應​​該工作的聯繫,即使用類似

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

看在的UITextField更改文本,縮短它在適當的時候在第一個問題的答案。

+1

在這種特殊情況下,符合UITextViewDelegate(或UITextFieldDelegate)優於滾動自己的通知(並且更易於調試)。我應該發佈我是如何解決這個問題的...... – 2009-07-17 19:05:03

10

我能夠通過符合UITextViewDelegate協議中的textViewDidChange:方法來限制輸入和粘貼的文本。

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

但我仍然認爲這樣一個醜陋的黑客攻擊,似乎蘋果應該提供某種UITextFields和UITextViews的「最大長度」屬性。

如果有人知道更好的解決方案,請告訴。

+0

這會導致崩潰時,我'撤消'。看到我的答案是「稍微」更好的解決方案。 – 2014-04-18 13:32:02

7

以我的經驗只是實施委託方法:

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

作品與粘貼。整個粘貼的字符串出現在replacementString:參數中。只需檢查它的長度,如果它比最大長度長,那麼只需從這個委託方法返回NO。這導致沒有被粘貼。另外,你可以像早先的答案一樣提供子字符串,但如果這太長了,這可以防止粘貼,如果這就是你想要的。

+0

如果文字太長不粘貼 – 2014-11-17 23:50:14

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

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

這一個不行! – fengd 2013-07-28 16:58:39

5

它插在textViewDidChange後更改文本:使應用程序如果用戶按下「撤消」後貼到崩潰。

我玩了很多,並能夠得到一個工作解決方案。基本上,邏輯是,如果總長度大於最大字符數,則不允許粘貼,檢測溢出的數量並只插入部分字符串。

使用此解決方案,您的粘貼板和撤消管理器將按預期工作。

- (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

這可以在沒有dispatch_async的情況下完成。 dispatch_async會導致iOS8上的新類型提前功能崩潰。我很快就會重新編寫代碼。 – 2014-11-18 03:47:20

0

此外,串長度爲「[字符串長度]」是一回事,但是一個通常需要截斷以字節計數在一定的編碼。我需要截斷鍵入和粘貼到UITextView到最大UTF8計數,以下是我如何做到這一點。 (爲UITextField做類似的事情是對讀者的一個練習。)

的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

謝謝你!這段代碼幫助我找出了替換文本字段中文本的正確方法!我做了一個迅速的3版本:https://gist.github.com/Blackjacx/2198d86442ec9b9b05c0801f4e392047 – blackjacx 2017-04-11 14:47:33

0

可以知道粘貼的字符串,如果您檢查string.lengthshouldChangeCharactersIn range:代表方法

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 
}