右对齐的UITextField空格键不会在iOS 7中前进光标

jkh*_*jkh 40 space objective-c uitextfield ios ios7

在我的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];
Run Code Online (Sandbox Code Playgroud)

在iOS 6中,当我输入"hello world"时,当我在"你好"之后点击空格键时,光标会前进一个空格.

在iOS 7中,当我按下空格键时光标不会前进.但是,当我在"世界"中键入"w"时,它会显示空格和w.

在iOS 7中按空格键时,如何使光标前进?

更新:

如果我将textField.textAlignment更改为UITextAlignmentLeft,则该空间将显示在iOS 7中.如果可能,我希望将其保持正确对齐.

tri*_*tan 44

这将是一个黑客攻击,但如果你真的需要这样看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;
}
Run Code Online (Sandbox Code Playgroud)

如果不清楚,textField:shouldChangeCharactersInRange:replacementString:是一个UITextFieldDelegate协议方法,所以在你的例子中,上面的方法将在viewcontroller中指定[textField setDelegate:self].

如果你希望你的常规空格后面,你会明显还需要记住更换的出现将文本转换回@"\u00a0"@" "获取串出文本字段时.

  • 你能解释为什么Apple在iOS7 +中这样做吗?我现在在8.1中看到它所以我认为它不是一个bug.是否存在我们应该考虑不绕过的变更背后的UI原理? (3认同)

git*_*rik 13

你必须用不间断的空格替换普通空格.最好为此更改事件触发操作:

  1. 在某处为UIControlEventEditingChanged文本字段上的事件添加操作:

    [myTextField addTarget:self action:@selector(replaceNormalSpacesWithNonBreakingSpaces)
                      forControlEvents:UIControlEventEditingChanged];
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然后实现replaceNormalSpacesWithNonBreakingSpaces方法:

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

这比使用更安全textField:shouldChangeCharactersInRange:replacementString:,因为如果NO从这个方法返回,你实际上是在说不应该更改指定的文本.这将导致不会触发更改事件(如IBActions textFieldEditingChanged:或UITextField的UIControlEventEditingChanged事件).

到处修复:

如果要对所有UITextField进行此修复,则可以创建一个类别,在启动UITextField时添加这些事件操作.在下面的示例中,我还在编辑结束时将非中断空格更改回正常空格,以便在其他地方使用数据时不会出现非中断空格的可能问题.请注意,此示例使用方法调配,因此它可能看起来有点奇怪,但它是正确的.

头文件:

//  UITextField+RightAlignedNoSpaceFix.h

#import <UIKit/UIKit.h>

@interface UITextField (RightAlignedNoSpaceFix)
@end
Run Code Online (Sandbox Code Playgroud)

实施文件:

//  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
Run Code Online (Sandbox Code Playgroud)


Jac*_*ong 11

以上所有答案都很棒,非常具有指示性!尤其是非常感谢的意思,问题下面答案.这是经过测试的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;
    }

}
Run Code Online (Sandbox Code Playgroud)

-

这是Swift 3!

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


mea*_*ers 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;
}
Run Code Online (Sandbox Code Playgroud)

不要担心stringByReplacingOccurrencesOfString每次都做的表现; UI中的文本相对于CPU速度非常短.

然后当你真的想从文本字段中获取值时:

NSString* text = [textField.text stringByReplacingOccurrencesOfString:@"\u00a0" withString:@" "];
Run Code Online (Sandbox Code Playgroud)

所以这是一个很好的对称.

  • 在`-textField:shouldChangeCharactersInRange:replacementString` 中返回NO 会禁止`UITextFieldTextDidChangeNotification`。所以你可以在你的方法中发送它`[[NSNotificationCenter defaultCenter] postNotificationName:UITextFieldTextDidChangeNotification object:textField];`以返回默认行为 (2认同)

小智 5

我想出了一个解决方案,它将UITextField类子类化并执行交换,而无需在任何地方复制和粘贴代码.这也避免了使用方法sizzle来解决这个问题.

@implementation CustomTextField

-(id) initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if( self ) {

        [self addSpaceFixActions];
    }

    return self;
}

- (void)addSpaceFixActions {
    [self addTarget:self action:@selector(replaceNormalSpaces) forControlEvents:UIControlEventEditingChanged];
    [self addTarget:self action:@selector(replaceBlankSpaces) forControlEvents:UIControlEventEditingDidEnd];
}


//replace normal spaces with non-breaking spaces.
- (void)replaceNormalSpaces {
    if (self.textAlignment == NSTextAlignmentRight) {
        UITextRange *textRange = self.selectedTextRange;
        self.text = [self.text stringByReplacingOccurrencesOfString:@" " withString:@"\u00a0"];
        [self setSelectedTextRange:textRange];
    }
}

//replace non-breaking spaces with normal spaces.
- (void)replaceBlankSpaces {
    self.text = [self.text stringByReplacingOccurrencesOfString:@"\u00a0" withString:@" "];
}
Run Code Online (Sandbox Code Playgroud)