Right aligned UITextField spacebar does not advance cursor in iOS 7

前端 未结 14 1627
执笔经年
执笔经年 2020-12-07 23:04

In my iPad app, I noticed different behavior between iOS 6 and iOS 7 with UITextFields.

I create the UITextField as follows:

UIButton *theButton = (U         


        
相关标签:
14条回答
  • 2020-12-07 23:22

    Old question but all the above solutions seem overly complicated. Here is how I solved the issue:

    I subscribed to two textfield events ->

    • TextFieldEditingDidBegin
    • TextFieldEditingEnded

    On TextFieldEditingDidBegin, I simple set textField.textAlignment to UITextAlignmentLeft. On TextFieldEditingEnded, I set textField.textAlignment back to UITextAlignmentRight.

    This worked flawlessly for me and I feel like its not a hack. Hope it helps!

    0 讨论(0)
  • 2020-12-07 23:23

    I solved this issue in my app using an by using a left-aligned text field, and then used AutoLayout to align the entire text field to the right. This simulates a right-aligned text field and handles trailing spaces without messing around with space characters etc.

    The main hurdle in this approach is that UITextField does not update it's intrinsic content size as the text changes. To get around this I subclassed UITextField to automatically calculate intrinsic content size as the text changes. Here's my subclass:

    @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
    

    And here's a fragment of my auto layout code, using the PureLayout library:

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

    Important points to note here:

    1. set content hugging priority on the text field
    2. use a NSLayoutRelationGreaterThanOrEqual relation between the left edge of text field and the view to the left of it (or superview's left edge).
    0 讨论(0)
  • 2020-12-07 23:24

    Fix right aligned text space removing by replacing space with non-breaking space

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        if (textField.textAlignment == NSTextAlignmentRight) {
            NSString *text = [textField.text stringByReplacingCharactersInRange:range withString:string];
            textField.text = [text stringByReplacingOccurrencesOfString:@" " withString:@"\u00a0"];
    
            UITextPosition *startPos = [textField positionFromPosition:textField.beginningOfDocument offset:range.location + string.length];
            UITextRange *textRange = [textField textRangeFromPosition:startPos toPosition:startPos];
            textField.selectedTextRange = textRange;
    
            return NO;
        }
    
        return YES;
    }
    

    And vice versa

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        // Replacing non-breaking spaces with spaces and remove obsolete data
        NSString *textString = [[textField.text stringByReplacingOccurrencesOfString:@"\u00a0" withString:@" "] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        textField.text = textString;
    }
    
    0 讨论(0)
  • 2020-12-07 23:24

    My following solution also takes care of the problem with the cursor jumping to the end when typing a space in the middle or beginning of the string. Also pasting a string is now processed correctly too.

    I also put in a check for email address fields and other checks, but the interesting part is the last part. It works perfectly for me, have yet to find a problem with it.

    You can directly copy/paste this in your project. Don't forget to implement the didBeginEditing and didEndEditing to replace the spaces with non-breaking spaces and back!

    - (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;
    }
    
    0 讨论(0)
  • 2020-12-07 23:26

    All the answers above are awesome and very indicative! Especially big thanks to meaning-matters's answer below. Here's a tested Swift 2.0 version. Remember to assign the delegate of the UITextField to your ViewController! Happy coding.

    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;
        }
    
    }
    

    --

    And here is 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;
        }
    }
    
    0 讨论(0)
  • 2020-12-07 23:27

    Swift 4 version:

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
        if var text = textField.text, range.location == text.count, string == " " {
            let noBreakSpace: Character = "\u{00a0}"
            text.append(noBreakSpace)
            textField.text = text
            return false
        }
        return true
    }
    
    0 讨论(0)
提交回复
热议问题