8

UITextView または UITextField に直接入力される文字列を制限する問題は、SO で以前に対処されています。

ただし、OS 3.0 ではコピー アンド ペーストが問題になります。上記の SO の質問の解決策では追加の文字の貼り付けが妨げられないためです (つまり、上記の解決策で構成されたフィールドに 10 文字を超える文字を入力することはできませんが、 100 文字を同じフィールドに簡単に貼り付けることができます)。

直接入力された文字列と貼り付けられた文字列のオーバーフローを防ぐ手段はありますか?

4

8 に答える 8

10

UITextViewDelegateプロトコル内のtextViewDidChange:メソッドに準拠することで、入力および貼り付けされたテキストを制限することができました。

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

しかし、私はまだこの種の醜いハックを考えており、AppleはUITextFieldsとUITextViewsのある種の「maxLength」プロパティを提供すべきだったようです。

誰かがより良い解決策を知っているなら、教えてください。

于 2009-07-17T19:09:04.803 に答える
7

私の経験では、デリゲートメソッドを実装するだけです:

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

貼り付けで動作します。貼り付けられた文字列全体が replacementString: 引数に含まれます。長さを確認し、最大長よりも長い場合は、このデリゲート メソッドから NO を返すだけです。これにより、何も貼り付けられません。または、以前の回答が示唆したように部分文字列にすることもできますが、これは、必要に応じて、長すぎる場合に貼り付けをまったく防止するために機能します。

于 2009-08-05T03:18:52.987 に答える
6

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;
}
于 2014-04-18T13:37:22.713 に答える
1

このコードでは、ユーザーは 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;
}
于 2018-04-19T10:28:33.513 に答える
0

上記でリンクした最初の質問の回答の1つが機能するはずです。つまり、次のようなものを使用します

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

UITextField 内のテキストの変更を監視し、必要に応じて短くします。

于 2009-07-17T13:22:03.920 に答える
0

また、「[文字列の長さ]」のような文字列の長さは 1 つのことですが、特定のエンコーディングでバイト数に切り詰める必要があることがよくあります。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;
}
于 2016-01-25T19:01:32.573 に答える
-1
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{

  if(string.length>10){
    return NO;
  }
  return YES;
}
于 2012-05-10T06:23:05.540 に答える