7

私はiOS開発を学んでいて、コントロールのさまざまなイベントを理解するのに苦労しています。テスト用に、ユーザーが次の形式で文字列を入力するUITextFieldがあります:XXXX-XXXX-XXXX-XXXX

各エントリの後のフィールドのテキストの長さを確認し、ハイフンを追加する必要があるかどうかを確認できるようにしたいと思います。このためにIBAction関数を設定しましたが、「Value Changed」イベントに割り当てると何も実行されず、「Editing Did End」に設定すると正常に機能しますが、ユーザーが終了したときにのみ呼び出されます。コントロール。

編集:追加するだけで、「EditingChanged」イベントによってクラッシュも発生します。これはスタックオーバーフローか、テキストの設定によってイベントハンドラーが再度呼び出されるものだと思います。

つまり、ユーザーがUITextFieldに文字を入力するたびにイベントハンドラーを設定する方法はありますか?

4

7 に答える 7

36

前の答えはひどく不十分であることに注意してください。天国はあなたのユーザーが間違った数字を入力することを禁じており、あえてそれを削除しようとしています!公平を期すために、ポスターはコードが完全に機能しない可能性があることを指摘しました。しかし、それではコンパイルすらできないので、購入者はフィルターがすでに高いことに注意してください。コンパイルエラーを修正してコードを試してみると、投稿者が指定した形式と一致しない入力に簡単になってしまう可能性があることがわかります。

これは、テキストフィールドを123-456-7890形式の電話番号に制限するために使用したソリューションです。他の数値形式の調整は簡単です。渡されたNSRangeの使用に注意してください。また、数値仮想キーボードを使用している場合でも、ユーザーはハードウェアキーボードを介して数字以外の文字を入力できるため、数字以外の文字を拒否する必要があります。

もう1つのメモ。数字の削除を少し簡単にするために、4桁目と7桁目の入力のにハイフンを追加します。3桁目と6桁目の後に追加する場合は、ぶら下がっているハイフンを削除する場合を処理する必要があります。以下のコードは、そのユースケースを回避します。

// Restrict entry to format 123-456-7890
- (BOOL)                textField:(UITextField *)textField
    shouldChangeCharactersInRange:(NSRange)range
                replacementString:(NSString *)string {

  // All digits entered
  if (range.location == 12) {
    return NO;
  }

  // Reject appending non-digit characters
  if (range.length == 0 &&
       ![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) {
    return NO;
  }

  // Auto-add hyphen before appending 4rd or 7th digit
  if (range.length == 0 &&
      (range.location == 3 || range.location == 7)) {
    textField.text = [NSString stringWithFormat:@"%@-%@", textField.text, string];
    return NO;
  }

  // Delete hyphen when deleting its trailing digit 
  if (range.length == 1 &&
      (range.location == 4 || range.location == 8))  {
    range.location--;
    range.length = 2;
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:@""];
    return NO;
  }

  return YES;
}
于 2012-07-10T16:53:23.823 に答える
6

ディンゴスカイの答えは良いですが、この解決策につまずく将来の人々を助けるという目的で、いくつかの問題があります。Dingoのソリューションでは、フォーマットと長さの範囲の場所のみを使用しているため、デリゲートの「ルール」に違反する長い数値文字列をフィールドに貼り付けることができます。(12文字を超えることができ、ハイフンは使用できません)。

簡単な解決策は、結果の文字列の長さを計算し、毎回再フォーマットすることです。

Dingoの回答の更新バージョンは次のとおりです。

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

    //calculate new length
     NSInteger moddedLength = textField.text.length-(range.length-string.length);

    // max size.
    if (moddedLength >= 13) {
        return NO;
    }

    // Reject non-number characters
    if (range.length == 0 &&![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) {
        return NO;
    }

    // Auto-add hyphen before appending 4rd or 7th digit
    if ([self range:range ContainsLocation:3] || [self range:range ContainsLocation:7]) {
        textField.text = [self formatPhoneString:[textField.text stringByReplacingCharactersInRange:range withString:string]];
        return NO;
    }

    return YES;
}

#pragma mark helpers

-(NSString*) formatPhoneString:(NSString*) preFormatted
{
    //delegate only allows numbers to be entered, so '-' is the only non-legal char.
    NSString* workingString = [preFormatted stringByReplacingOccurrencesOfString:@"-" withString:@""];

    //insert first '-'
    if(workingString.length > 3)
    {
        workingString = [workingString stringByReplacingCharactersInRange:NSMakeRange(3, 0) withString:@"-"];
    }

    //insert second '-'
    if(workingString.length > 7)
    {
        workingString = [workingString stringByReplacingCharactersInRange:NSMakeRange(7, 0) withString:@"-"];
    }

    return workingString;

}

-(bool) range:(NSRange) range ContainsLocation:(NSInteger) location
{
    if(range.location <= location && range.location+range.length >= location)
    {
        return true;
    }

    return false;
}
于 2013-12-20T17:07:15.537 に答える
5

このような場合は、UITextFieldDelegateを使用して、ユーザーが新しい文字を入力するたびに検出することをお勧めします。テキストフィールドのデリゲートを次のように設定します。

[textField setDelegate:self];

次に、必要に応じてデリゲートメソッドを実装します。

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder]; // hide the keyboard
    return NO;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // every time the length reaches four, it gets reset to 0 and a '-' is added.
    static int currentLength = 0;
    if ((currentLength += [string length]) == 4) {
        currentLength = 0;
        [textField setText:[NSString stringWithFormat:@"%@%@%c", [textField text], string, '-'];
        return NO;
    }
    return YES;
}

これは完全には機能しないかもしれませんが、お役に立てば幸いです。

于 2011-08-06T18:11:49.680 に答える
2

これが、カーソルを移動したり、テキストの範囲を削除したり、有効なテキストを貼り付けたりする場合でも機能する私のアプローチです。基本的に、私のアプローチは、毎回テキストをリセットし、必要に応じてハイフンを追加することです。複雑なのは、ユーザーがカーソルを文字列の中央に移動した場合でも、カーソルの位置が正しい場所にリセットされることです。残念ながら、考慮すべきケースはたくさんあります。

確かに、このような単純なタスクでは途方もなく複雑です(間違いなく大規模なクリーンアップを使用できます)。また、少し非効率的ですが、ここでは厳密に計算を行っているわけではありません。私の知る限り、これはここで最も確実なソリューションです。私が間違っていることを証明する人を歓迎します。

-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (range.location == 12 || (textField.text.length >= 12 && range.length == 0) || string.length + textField.text.length > 12 ) {
            return NO;
    }

   // Reject appending non-digit characters
   if (range.length == 0 &&
       ![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) {
       return NO;
   }

    UITextRange* selRange = textField.selectedTextRange;
    UITextPosition *currentPosition = selRange.start;
    NSInteger pos = [textField offsetFromPosition:textField.beginningOfDocument toPosition:currentPosition];
    if (range.length != 0) { //deleting
        if (range.location == 3 || range.location == 7) { //deleting a dash
            if (range.length == 1) {
                range.location--;
                pos-=2;
            }
            else {
                pos++;
            }
        }
        else {
            if (range.length > 1) {
                NSString* selectedRange = [textField.text substringWithRange:range];
                NSString* hyphenless = [selectedRange stringByReplacingOccurrencesOfString:@"-" withString:@""];
                NSInteger diff = selectedRange.length - hyphenless.length;
                pos += diff;
            }
            pos --;
        }
    }

    NSMutableString* changedString = [NSMutableString stringWithString:[[textField.text stringByReplacingCharactersInRange:range withString:string] stringByReplacingOccurrencesOfString:@"-" withString:@""]];
    if (changedString.length > 3) {
        [changedString insertString:@"-" atIndex:3];
        if (pos == 3) {
            pos++;
        }
    }
    if (changedString.length > 7) {
        [changedString insertString:@"-" atIndex:7];
        if (pos == 7) {
            pos++;
        }
    }
    pos += string.length;

    textField.text = changedString;
    if (pos > changedString.length) {
        pos = changedString.length;
    }
    currentPosition = [textField positionFromPosition:textField.beginningOfDocument offset:pos];

    [textField setSelectedTextRange:[textField textRangeFromPosition:currentPosition toPosition:currentPosition]];
    return NO;
}

または:このhttps://github.com/romaonthego/REFormattedNumberFieldを使用してください

于 2014-05-10T23:52:09.363 に答える
2

少し調べてみると、以下の解決策で新しい文字列を等間隔で自動的に追加/削除できると思います。

説明: 1。新しい文字を挿入します

    Text        :   XXXX-XXXX-
    Location    :   0123456789

    Objective   :   We've to insert new character's at locations 4,9,14,19,etc. Since equal spacing should be 4.

 Let's assume   y = The location where the new charcter should be inserted,
                z = Any positive value i.e.,[4 in our scenario] and 
                x = 1,2,3,...,n
 Then,
        =>  zx + x - 1 = y              e.g., [ 4 * 1 + (1-1) = 4 ; 4 * 2 + (2 - 1) = 9 ; etc. ]
        =>  x(z + 1) - 1 = y    
        =>  x(z + 1) = (1 + y)
        =>  ***x = (1 + y) % (z + 1)***         e.g., [ x = (1 + 4) % (4 + 1) => 0; x = (1 + 9) % (4 + 1) => 0 ]

 The reason behind finding 'x' leads to dynamic calculation, because we can find y, If we've 'z' but the ultimate objective is to find the sequence 'x'. Of course with this equation we may manipulate it in different ways to achieve many solutions but it is one of them.

 2. Removing two characters (-X) at single instance while 'delete' keystroke

    Text        :   XXXX-XXXX-
    Location    :   0123456789

    Objective   :   We've to remove double string when deleting keystroke pressed at location 5,10,15,etc. i.e., The character prefixed with customized space indicator

 Note: 'y' can't be zero


        =>  zx + x = y              e.g., [ 4 * 1 + 1 = 5 ; 4 * 2 + 2 = 10; 4 * 3 + 3 = 15; etc.]
        =>  x(z + 1) = y
        =>  ***x = y % (z + 1)***         e.g., [ x = (5 % (4 + 1)) = 0; x = (10 % (4 + 1)) = 0; etc. ]

Swiftのソリューション:

let z = 4, intervalString = " "

func canInsert(atLocation y:Int) -> Bool { return ((1 + y)%(z + 1) == 0) ? true : false }

func canRemove(atLocation y:Int) -> Bool { return (y != 0) ? (y%(z + 1) == 0) : false }

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

        let nsText = textField.text! as NSString

        if range.length == 0 && canInsert(atLocation: range.location) {
            textField.text! = textField.text! + intervalString + string
            return false
        }

        if range.length == 1 && canRemove(atLocation: range.location) {
            textField.text! = nsText.stringByReplacingCharactersInRange(NSMakeRange(range.location-1, 2), withString: "")
            return false
        }

        return true
    }
于 2016-07-25T06:09:01.110 に答える
1

あなたはこれを試すことができます:

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

それは本当にそれで動作するはずです、あなたはまたいくつかのコードを投稿するべきです。イベントに登録した後、文字列の長さを確認し、ハイフンを追加する必要があります。

于 2011-08-06T17:32:32.533 に答える
0

現在受け入れられている回答は、テキストフィールドへのコピー/貼り付けを考慮していません

デリゲートの「shouldChangeCharactersInRange」を使用する代わりに、テキストフィールドのIBActionをTextDidChangeアクションに接続します。次に、次のコードを追加します。

- (IBAction)textFieldDidChange:(UITextField *)sender {
    if (sender.text.length > 0) {
        NSString *text = sender.text;
        text = [text stringByReplacingOccurrencesOfString:@"-" withString:@""];
        text = [text substringToIndex:MIN(20, text.length)];

        NSMutableArray *parts = [NSMutableArray array];
        int counter = 0;
        while (text.length > 0) {
            [parts addObject:[text substringToIndex:MIN(5, text.length)]];
            if (text.length > 5) {
                text = [text substringFromIndex:5];
            } else {
                text = @"";
            }
            counter ++;
        }
        text = [parts objectAtIndex:0];
        [parts removeObjectAtIndex:0];
        for (NSString *part in parts) {
            text = [text stringByAppendingString:@"-"];
            text = [text stringByAppendingString:part];
        }

        sender.text = text;
    }
}

これは正しい方法です。ユーザーがテキストフィールドにテキストを貼り付ける場合、貼り付けたすべてのテキストをそれに応じてフォーマットする必要があるためです(一度に1文字だけではありません)。

于 2014-07-18T00:31:05.730 に答える