代码之家  ›  专栏  ›  技术社区  ›  Kevin L.

限制uitextView或uitextField中粘贴的字符串长度

  •  5
  • Kevin L.  · 技术社区  · 15 年前

    限制直接输入到uitextView或uitextField中的字符串的问题在下面已经解决了:

    但是,现在使用OS 3.0复制和粘贴成为一个问题,因为上面的解决方案不会阻止粘贴其他字符(即,您不能在配置有上述解决方案的字段中键入超过10个字符,但可以轻松地将100个字符粘贴到同一字段中)。

    是否有防止直接输入字符串的方法 粘贴的字符串溢出?

    8 回复  |  直到 7 年前
        1
  •  10
  •   Kevin L.    15 年前

    我可以通过遵循uitextViewDelegate协议中的textViewDidChange:方法来限制输入和粘贴的文本。

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

    但我仍然认为这是一种丑陋的黑客行为,苹果似乎应该提供uitextfields和uitextviews的某种“maxlength”属性。

    如果有人知道更好的解决方案,请告诉我。

        2
  •  7
  •   Rob    15 年前

    以我刚刚实施委托方法的经验:

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

    可用于粘贴。整个粘贴的字符串出现在replacementstring:参数中。只需检查它的长度,如果它比您的最大长度长,那么只需从这个委托方法返回no。这不会导致粘贴任何内容。或者,您可以像前面建议的答案那样对其进行子串,但如果太长(如果这是您想要的),则这可以完全防止粘贴。

        3
  •  6
  •   Brad G    10 年前

    在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;
    }
    
        4
  •  0
  •   David Maymudes    15 年前

    上面链接到的第一个问题中的一个答案应该有效,即使用类似于

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

    监视uitextfield中文本的更改并在适当时缩短它。

        5
  •  0
  •   Pierre Houston    9 年前

    另外,字符串长度(如'[string length]'中的字符串长度)是一回事,但通常需要在特定编码中将其截断为字节数。我需要将输入和粘贴到uitextview中的操作截断为最大utf8计数,下面是我的操作方法。(对读者来说,为uitextfield做类似的事情是一项练习。)

    nsstring+trunceutf8.h

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

    nsstring+trunceutf8.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]);
    //    }
    

    我的视图控制器.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;
    }
    
        6
  •  0
  •   Rugmangathan    8 年前

    如果你检查一下 string.length 在里面 shouldChangeCharactersIn 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
    }
    
        7
  •  0
  •   alekseevpg    6 年前

    此代码不允许用户输入超过maxcharacters的字符。 如果粘贴的文本超过此限制,则“粘贴”命令将不起任何作用。

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
        return newText.count <= maxCharacters;
    }
    
        8
  •  -1
  •   Kjuly    12 年前
    -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    
      if(string.length>10){
        return NO;
      }
      return YES;
    }