0

私が書いているiOSアプリケーションの場合、ユーザーが限られたテキストを挿入できるUITextViewを使用しています。

テキストビューには2つの制限があります。

  1. 行は30文字以内にする必要があります
  2. UITextViewには20行のテキストしか含めることができません。

つまり、最大は30文字の20行です。

ユーザーがUITextViewにテキストを入力していて、現在の文が30文字の場合、新しい行\n(その行の最後の単語の前)を自動的に挿入し、最後の単語とカーソルを下の行に強制します。

ユーザーが30文字の20行(またはもっと簡単に言うと、最後の行に30文字の20行)がある場合、入力をブロックしたいと思います。

さて、これのほとんどはかなり「単純」ですが、私が持っているコードは、前の行にテキストを挿入するような境界の場合を考慮していません。

Appleのドキュメントを見回しましたが、UITextViewでこの種のワードラップを実際に強制する方法を見つけることができません。

私の試みは、これらすべてをshouldChangeTextInRangeデリゲートメソッドで処理することです(コードをもう少し冗長にしたので、少し読みやすくなりました)。

#define MAX_LENGTH_LINE 30
#define MAX_LENGTH_ROWS 20

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    // Check for backspaces, they should always be allowed?
    if ([text length] == 0 && ![text isEqualToString:@"\n"])
        return YES;

    NSArray* lines = [textView.text componentsSeparatedByString:@"\n"];

    // Check if there are a maximum of lines and the last line is already maxed out
    NSString* lastLine = [lines objectAtIndex:[lines count] - 1];

    if (([lines count] == MAX_LENGTH_ROWS) &&
        (lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE) &&
        ([text length] > 0))
        return NO;


    if ((lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE))
    {
        NSRange range = [textView.text rangeOfString:@" " options:NSBackwardsSearch];
        NSRange breakRange = [textView.text rangeOfString:@"\n" options:NSBackwardsSearch];

        if (breakRange.location == NSNotFound)
            breakRange = NSMakeRange(0, 1);

        if (range.location == NSNotFound) {
            range = NSMakeRange(0, 1);
        }

        if (range.location > breakRange.location)
        {
            textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(range.location, 1) withString:@"\n"];
        }
        else
        {
            textView.text = [textView.text stringByAppendingString:@"\n"];
        }
    }

    if ([text isEqualToString:@"\n"])
    {
        if ([lines count] == MAX_LENGTH_ROWS)
            return NO;
        else {
            return YES;
        }
        NSRange range = NSMakeRange(textView.text.length - 1, 1);
        [textView scrollRangeToVisible:range];
    }

    return YES;
}

その間、私はしばらくこれにいて、今それを失いました。UITextViewを20行/30文字の制限に制限するためのポインタを提供できる人はいますか?

4

2 に答える 2

0

これは全体的な目標に反するかもしれませんが、私の頭の中で最も簡単な答えは、ユーザーが文字を追加するたびに文字列を再解析することです。その場合、キャラクターがどこに追加されたかは問題ではありません。これをすべて shouldChangeTextInRange: で行う代わりに、textViewDidChange: で行います。UITextViewDelegate である必要があり、ユーザーが許可された制限を超えて文字を追加しようとした場合に備えて、最後に成功したユーザー テキストの更新を保持する単一のクラス NSString が必要です。

このようなもの:

-(void)textViewDidChange:(UITextView *)textView
{
    //Get the textview without any new line characters
    NSMutableString *temporaryString = [NSMutableString stringWithString:[textView.text stringByReplacingOccurrencesOfString:@"\n" withString:@" "]];
    bool updatePossible = true;

    int i = 0, numberOfLinesSoFar = 0;
    while(i + 30 < [temporaryString length])
    {
        //Go 30 characters in and start the reverse search for a word separation
        i += 30;
        int j = i;
        //Get the location of the final word separation in the current line
        while(j >= i && [temporaryString characterAtIndex:j] != ' ')
        {
            j--;
        }

        //This means we found a word separation
        if(j > i)
        {
            i = j;
            [temporaryString replaceCharactersInRange:NSMakeRange(i,1) withString:@"\n"];
        }
        //We didn't find a word separation
        else
        {
            //Here we will just have to break the line at 30.
            [temporaryString insertString:@"\n" atIndex:i];
        }

        numberOfLinesSoFar++;

        //Check if we just wrote line 20 and still have characters to go.
        if(numberOfLinesSoFar > 19 && i < [temporaryString length])
        {
            //Revert user change to the last successful character addition
            textView.text = lastSuccessfulViewString;
            updatePossible = false;
            break;
        }
    }

    if(updatePossible)
    {
        //If we are within the limits then update the global string (for undoing character additions) and the textview
        textView.text = temporaryString;
        lastSuccessfulViewString = temporaryString;
    }
}

これにより、ユーザーは独自の改行文字を入れることができなくなりますが、それはいくつかの if then ステートメントで処理できます。

于 2013-01-16T15:27:02.003 に答える
0

少しいじった後、サブビューとして UITextView を含むコントロールを作成しました。

このコントロールでテキストの折り返しを処理し、デリゲート メソッドをデリゲートとして登録されたビューに転送します。

他の人にも役立つかもしれないので、ここに BitBucket へのリンクを投稿します。

PS。まだ非常に冗長ですが、これは私のケースでこれをどのように解決したかを示すためのものです。

https://bitbucket.org/depl0y/sbframework/src/master/SBFramework/Views/SBTextView?at=master

于 2013-01-24T06:11:05.760 に答える