44

私の iPad アプリでは、iOS 6 と iOS 7 で UITextFields の動作が異なることに気付きました。

次のように UITextField を作成します。

UIButton *theButton = (UIButton*)sender;
UITextField *textField = [[UITextField alloc] initWithFrame:[theButton frame]];

[textField setDelegate:self];
[textField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[textField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight];

textField.textAlignment = UITextAlignmentRight;
textField.keyboardType = UIKeyboardTypeDefault;

...

[textField becomeFirstResponder];

iOS 6 では、「hello world」と入力すると、「hello」の後にスペースバーを押すと、カーソルが空白スペースを進めます。

iOS 7 では、スペースバーを押してもカーソルが進みません。しかし、「ワールド」に「w」を入力すると、スペースと w が表示されます。

iOS 7 でスペースバーを押したときにカーソルを進めるにはどうすればよいですか?

アップデート:

textField.textAlignment を UITextAlignmentLeft に変更すると、iOS 7 でスペースが表示されます。可能であれば、右揃えにしたいと思います。

4

14 に答える 14

49

ちょっとしたハックになりますが、iOS6 のように見せるために本当に必要な場合は、書かれているようにスペースを改行しないスペースに置き換えることができます。扱いが違います。サンプル コードは次のようになります。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // only when adding on the end of textfield && it's a space
    if (range.location == textField.text.length && [string isEqualToString:@" "]) {
        // ignore replacement string and add your own
        textField.text = [textField.text stringByAppendingString:@"\u00a0"];
        return NO;
    }
    // for all other cases, proceed with replacement
    return YES;
}

明確でない場合textField:shouldChangeCharactersInRange:replacementString:UITextFieldDelegateプロトコルメソッドであるため、例では、上記のメソッドは で指定されたビューコントローラーにあり[textField setDelegate:self]ます。

@"\u00a0"通常のスペースを元に戻したい場合は、テキストフィールドから文字列を取得する@" "ときに、出現箇所を に置き換えて、テキストを元に戻すことを忘れないでください。

于 2013-11-21T18:49:27.173 に答える
14

上記のすべての回答は素晴らしく、非常に示唆的です! 以下の意味事項回答に特に感謝します。これは、テスト済みのSwift 2.0バージョンです。UITextFieldのデリゲートを ViewControllerに割り当てることを忘れないでください! ハッピーコーディング。

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

    if (textField == self.desiredTextField) {
        var oldString = textField.text!
        let newRange = oldString.startIndex.advancedBy(range.location)..<oldString.startIndex.advancedBy(range.location + range.length)
        let newString = oldString.stringByReplacingCharactersInRange(newRange, withString: string)
        textField.text = newString.stringByReplacingOccurrencesOfString(" ", withString: "\u{00a0}");
        return false;
    } else {
        return true;
    }

}

--

そしてこちらがSwift3!

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if (textField == self.textfield) {
        let oldString = textField.text!
        let newStart = oldString.index(oldString.startIndex, offsetBy: range.location)
        let newEnd = oldString.index(oldString.startIndex, offsetBy: range.location + range.length)
        let newString = oldString.replacingCharacters(in: newStart..<newEnd, with: string)
        textField.text = newString.replacingOccurrences(of: " ", with: "\u{00a0}")
        return false;
    } else {
        return true;
    }
}
于 2016-03-05T05:30:03.083 に答える
13

通常のスペースを非改行スペースに置き換える必要があります。これには、変更イベントでアクションをトリガーするのが最善です。

  1. テキストフィールドのどこかにUIControlEventEditingChangedイベントのアクションを追加します。

    [myTextField addTarget:self action:@selector(replaceNormalSpacesWithNonBreakingSpaces)
                      forControlEvents:UIControlEventEditingChanged];
    
  2. replaceNormalSpacesWithNonBreakingSpaces次に、メソッドを実装します。

    - (void)replaceNormalSpacesWithNonBreakingSpaces
    {
        self.text = [self.text stringByReplacingOccurrencesOfString:@" "
                                                         withString:@"\u00a0"];
    }
    

これは を使用するよりも安全ですtextField:shouldChangeCharactersInRange:replacementString:。なぜなら、このメソッドから戻った場合、NO実際には、指定されたテキストを変更すべきではないと言っているからです。これにより、変更イベント (IBActionstextFieldEditingChanged:や UITextField のUIControlEventEditingChangedイベントなど) がトリガーされなくなります。

どこでも修正してください:

すべての UITextField に対してこの修正が必要な場合は、UITextField が開始されたときにこれらのイベント アクションを追加するカテゴリを作成できます。以下の例では、編集が終了したときに非改行スペースを通常のスペースに戻して、データが別の場所で使用されたときに非改行スペースの問題が発生しないようにしています。この例ではメソッドの入れ替えを使用しているため、少し奇妙に見えるかもしれませんが、正しいことに注意してください。

ヘッダー ファイル:

//  UITextField+RightAlignedNoSpaceFix.h

#import <UIKit/UIKit.h>

@interface UITextField (RightAlignedNoSpaceFix)
@end

実装ファイル:

//  UITextField+RightAlignedNoSpaceFix.m

#import "UITextField+RightAlignedNoSpaceFix.h"

@implementation UITextField (RightAlignedNoSpaceFix)

static NSString *normal_space_string = @" ";
static NSString *non_breaking_space_string = @"\u00a0";

+(void)load
{
    [self overrideSelector:@selector(initWithCoder:)
              withSelector:@selector(initWithCoder_override:)];

    [self overrideSelector:@selector(initWithFrame:)
              withSelector:@selector(initWithFrame_override:)];
}

/**
 * Method swizzles the initWithCoder method and adds the space fix
 * actions.
 */
-(instancetype)initWithCoder_override:(NSCoder*)decoder
{
    self = [self initWithCoder_override:decoder];
    [self addSpaceFixActions];
    return self;
}

/**
 * Method swizzles the initWithFrame method and adds the space fix
 * actions.
 */
-(instancetype)initWithFrame_override:(CGRect)frame
{
    self = [self initWithFrame_override:frame];
    [self addSpaceFixActions];
    return self;
}

/**
 * Will add actions on the text field that will replace normal 
 * spaces with non-breaking spaces, and replaces them back after
 * leaving the textfield.
 *
 * On iOS 7 spaces are not shown if they're not followed by another
 * character in a text field where the text is right aligned. When we
 * use non-breaking spaces this issue doesn't occur.
 *
 * While editing, the normal spaces will be replaced with non-breaking
 * spaces. When editing ends, the non-breaking spaces are replaced with
 * normal spaces again, so that possible problems with non-breaking
 * spaces won't occur when the data is used somewhere else.
 */
- (void)addSpaceFixActions
{

    [self addTarget:self action:@selector(replaceNormalSpacesWithNonBreakingSpaces)
               forControlEvents:UIControlEventEditingDidBegin];

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

    [self addTarget:self action:@selector(replaceNonBreakingSpacesWithNormalSpaces)
               forControlEvents:UIControlEventEditingDidEnd];

}

/**
 * Will replace normal spaces with non-breaking spaces.
 */
- (void)replaceNormalSpacesWithNonBreakingSpaces
{
    self.text = [self.text stringByReplacingOccurrencesOfString:normal_space_string
                                                     withString:non_breaking_space_string];
}

/**
 * Will replace non-breaking spaces with normal spaces.
 */
- (void)replaceNonBreakingSpacesWithNormalSpaces
{
    self.text = [self.text stringByReplacingOccurrencesOfString:non_breaking_space_string
                                                     withString:normal_space_string];
}

@end
于 2014-03-19T16:26:47.100 に答える
5

これは、貼り付けと編集にも常に機能するソリューションです(つまり、複数のスペースを含むテキストを追加/削除する場合)。

- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string
{
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
    textField.text = [textField.text stringByReplacingOccurrencesOfString:@" " withString:@"\u00a0"];

    return NO;
}

stringByReplacingOccurrencesOfString毎回行うパフォーマンスについて心配する必要はありません。UI のテキストは、CPU 速度に比べて非常に短いです。

次に、実際にテキストフィールドから値を取得したい場合:

NSString* text = [textField.text stringByReplacingOccurrencesOfString:@"\u00a0" withString:@" "];

これはきれいに左右対称です。

于 2014-03-05T22:44:15.067 に答える
4

triazotan回答を Swift3 に変換しました。

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

    if (range.location == textField.text?.characters.count && string == " ") {
        let noBreakSpace: Character = "\u{00a0}"
        textField.text = textField.text?.append(noBreakSpace)
        return false
    }
    return true
}
于 2017-01-24T09:41:35.270 に答える
3

古い質問ですが、上記の解決策はすべて複雑すぎるようです。これが私が問題を解決した方法です:

2 つのテキスト フィールド イベントをサブスクライブしました ->

  • TextFieldEditingDidBegin
  • TextFieldEditingEnded

TextFieldEditingDidBegin で、textField.textAlignment を UITextAlignmentLeft に設定するだけです。TextFieldEditingEnded で、textField.textAlignment を UITextAlignmentRight に戻します。

これは私にとって完璧に機能し、ハックではないように感じます. それが役に立てば幸い!

于 2014-09-05T20:23:15.657 に答える
1

左揃えのテキスト フィールドを使用してアプリでこの問題を解決し、AutoLayout を使用してテキスト フィールド全体を右揃えにしました。これは、右揃えのテキスト フィールドをシミュレートし、スペース文字などをいじることなく末尾のスペースを処理します。

このアプローチの主な障害は、UITextField がテキストが変更されたときに固有のコンテンツ サイズを更新しないことです。これを回避するために、UITextField をサブクラス化して、テキストの変更に応じて固有のコンテンツ サイズを自動的に計算しました。ここに私のサブクラスがあります:

@implementation PLResizingTextField

- (instancetype)init {
    self = [super init];
    if(self) {
        [self addTarget:self action:@selector(invalidateIntrinsicContentSize) forControlEvents:UIControlEventEditingChanged];
    }
    return self;
}

- (CGSize)intrinsicContentSize {
    CGSize size = [super intrinsicContentSize];
    NSString *text = self.text.length ? self.text : self.placeholder;

    CGRect rect = [text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX,CGFLOAT_MAX)
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@{NSFontAttributeName:self.font}
                                     context:nil];
    size.width = CGRectGetWidth(rect);

    return size;
}

@end

PureLayout ライブラリを使用した自動レイアウト コードの一部を次に示します。

[textField autoPinEdgeToSuperviewEdge:ALEdgeTrailing
                            withInset:10];
[textField autoPinEdge:ALEdgeLeading
                toEdge:ALEdgeTrailing
                ofView:cell.textLabel
            withOffset:10
              relation:NSLayoutRelationGreaterThanOrEqual];
[textField setContentHuggingPriority:UILayoutPriorityDefaultHigh
                             forAxis:UILayoutConstraintAxisHorizontal];

ここで注意すべき重要な点:

  1. テキストフィールドにコンテンツの優先度を設定する
  2. NSLayoutRelationGreaterThanOrEqualテキスト フィールドの左端とその左側のビュー (またはスーパービューの左端) の間の関係を使用します。
于 2015-06-09T23:52:33.393 に答える
0

私の次の解決策は、文字列の途中または最初にスペースを入力すると、カーソルが最後にジャンプするという問題にも対処します。また、文字列の貼り付けも正しく処理されるようになりました。

メールアドレス欄のチェックなども入れていますが、面白いのは最後の部分です。それは私にとって完璧に機能しますが、まだ問題を見つけていません。

これをプロジェクトに直接コピーして貼り付けることができます。didBeginEditing と didEndEditing を実装して、スペースを改行しないスペースに置き換えて元に戻すことを忘れないでください。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField.textAlignment != NSTextAlignmentRight) //the whole issue only applies to right aligned text
        return YES;

    if (!([string isEqualToString:@" "] || string.length > 1)) //string needs to be a space or paste action (>1) to get special treatment
        return YES;

    if (textField.keyboardType == UIKeyboardTypeEmailAddress) //keep out spaces from email address field
    {
        if (string.length == 1)
            return NO;
        //remove spaces and nonbreaking spaces from paste action in email field:
        string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
        string = [string stringByReplacingOccurrencesOfString:@"\u00a0" withString:@""];
    }

    //special treatment starts here
    string = [string stringByReplacingOccurrencesOfString:@" " withString:@"\u00a0"];
    UITextPosition *beginning = textField.beginningOfDocument;
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
    UITextPosition *start = [textField positionFromPosition:beginning offset:range.location+string.length];
    UITextPosition *end = [textField positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end];
    [textField setSelectedTextRange:textRange];

    return NO;
}
于 2014-11-30T18:54:59.757 に答える