【问题标题】:UITextField, automatically move to next after 1 characterUITextField,1个字符后自动移动到下一个
【发布时间】:2011-01-08 22:22:12
【问题描述】:

场景:我有 4 个 UITextFields,只接受 1 个字符。很简单。

问题:在我输入 1 个字符后,我希望下一个 TextField 自动变为活动状态,而无需按下下一个(即我正在使用 UIKeyboardTypeNumberPad,并且没有 NEXT 按钮。(我知道我实际上可以创建一个下一个以编程方式按钮,但我不想走那么远,只需要在输入 1 个字符后下一个字段自动变为活动状态。

#define MAX_LENGTH 1

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
    for (int i = 0; i < [string length]; i++) {
    unichar c = [string characterAtIndex:i];
        if (![myCharSet characterIsMember:c]) {
            return NO;
        }
    }
        NSUInteger newLength = [textField.text length] + [string length] - range.length;
        return (newLength > 1) ? NO : YES;
}


-(BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (textField == pc1) {
        [pc2 becomeFirstResponder];
    }else if (textField == pc2) {
        [pc3 becomeFirstResponder];
    }else if (textField == pc3) {
        [pc4 becomeFirstResponder];
    }else if (textField == pc4) {
        [textField resignFirstResponder];
    }
    return YES;
}

【问题讨论】:

    标签: delegates keyboard uitextfield


    【解决方案1】:

    我通过修改我在这里找到的一些代码得出了一个解决方案: http://www.thepensiveprogrammer.com/2010/03/customizing-uitextfield-formatting-for.html

    首先将您的视图控制器设置为文本字段的委托。

    然后做这样的事情:

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {   
        BOOL shouldProcess = NO; //default to reject
        BOOL shouldMoveToNextField = NO; //default to remaining on the current field
    
        int insertStringLength = [string length];
        if(insertStringLength == 0){ //backspace
            shouldProcess = YES; //Process if the backspace character was pressed
        }
        else {
            if([[textField text] length] == 0) {
                shouldProcess = YES; //Process if there is only 1 character right now
            }
        }
    
        //here we deal with the UITextField on our own
        if(shouldProcess){
            //grab a mutable copy of what's currently in the UITextField
            NSMutableString* mstring = [[textField text] mutableCopy];
            if([mstring length] == 0){
                //nothing in the field yet so append the replacement string
                [mstring appendString:string];
    
                shouldMoveToNextField = YES;
            }
            else{
                //adding a char or deleting?
                if(insertStringLength > 0){
                    [mstring insertString:string atIndex:range.location];
                }
                else {
                    //delete case - the length of replacement string is zero for a delete
                    [mstring deleteCharactersInRange:range];
                }
            }
    
            //set the text now
            [textField setText:mstring];
    
            [mstring release];
    
            if (shouldMoveToNextField) {
                //
                //MOVE TO NEXT INPUT FIELD HERE
                //
            }
        }
    
        //always return no since we are manually changing the text field
        return NO;
    }
    

    【讨论】:

      【解决方案2】:

      SWIFT 3 的更新代码

      @IBOutlet weak var tf1: UITextField!
      @IBOutlet weak var tf2: UITextField!
      @IBOutlet weak var tf3: UITextField!
      @IBOutlet weak var tf4: UITextField!
      override func viewDidLoad() {
          super.viewDidLoad()
          tf1.delegate = self
          tf2.delegate = self
          tf3.delegate = self
          tf4.delegate = self
      
      
          tf1.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
          tf2.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
          tf3.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
          tf4.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
      
      }
      override func viewWillAppear(_ animated: Bool) {
          super.viewWillAppear(true)
          tf1.becomeFirstResponder()
      
      }
      func textFieldDidChange(textField: UITextField){
      
          let text = textField.text
      
          if text?.utf16.count==1{
              switch textField{
              case tf1:
                  tf2.becomeFirstResponder()
              case tf2:
                  tf3.becomeFirstResponder()
              case tf3:
                  tf4.becomeFirstResponder()
              case tf4:
                  tf4.resignFirstResponder()
              default:
                  break
              }
          }else{
      
          }
      }
      

      【讨论】:

        【解决方案3】:

        我知道这是一个非常老问题,但这是我的方法,它只允许单个数值跨四个 UITextFields,并自动“切换”到下一个(pin1-pin4 每个代表一个PIN 码数字大声笑,并保留为属性):

        -(BOOL)textFieldShouldReturn:(UITextField*)textField;
        {
            if (textField == pin1)
            {
                [pin2 becomeFirstResponder];
            }
            else if (textField == pin2)
            {
                [pin3 becomeFirstResponder];
            }
            else if (textField == pin3)
            {
                [pin4 becomeFirstResponder];
            }
        
            return NO;
        }
        
        - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
        {
            // This allows numeric text only, but also backspace for deletes
            if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
                return NO;
        
            NSUInteger oldLength = [textField.text length];
            NSUInteger replacementLength = [string length];
            NSUInteger rangeLength = range.length;
        
            NSUInteger newLength = oldLength - rangeLength + replacementLength;
        
            // This 'tabs' to next field when entering digits
            if (newLength == 1) {
                if (textField == pin1)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin2 afterDelay:0.2];
                }
                else if (textField == pin2)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin3 afterDelay:0.2];
                }
                else if (textField == pin3)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin4 afterDelay:0.2];
                }
            }
            //this goes to previous field as you backspace through them, so you don't have to tap into them individually
            else if (oldLength > 0 && newLength == 0) {
                if (textField == pin4)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin3 afterDelay:0.1];
                }
                else if (textField == pin3)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin2 afterDelay:0.1];
                }
                else if (textField == pin2)
                {
                    [self performSelector:@selector(setNextResponder:) withObject:pin1 afterDelay:0.1];
                }
            }
        
            return newLength <= 1;
        }
        
        - (void)setNextResponder:(UITextField *)nextResponder
        {
            [nextResponder becomeFirstResponder];
        }
        

        【讨论】:

          【解决方案4】:

          以下内容适用于 Swift 5,并将文本字段作为数组处理,而不是单个字段。

          import UIKit
          
          class MyViewController: UIViewController, UITextFieldDelegate {
          
          @IBOutlet var digitFields: [UITextField]!
          
          override func viewDidLoad() {
              super.viewDidLoad()
          
              digitFields.forEach {
                  configureDigitField($0)
              }
          }
          
          override func viewWillAppear(_ animated: Bool) {
              super.viewWillAppear(animated)
              digitFields[0].becomeFirstResponder()
          }
          
          fileprivate func configureDigitField(_ digitField: UITextField) {
              digitField.delegate = (self as UITextFieldDelegate)
              digitField.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: UIControl.Event.editingChanged)
          }
          
          // Move to next field in digit fields if the value is populated
          @objc fileprivate func textFieldDidChange(textField: UITextField) {
              if textField.text?.count == 1 {
                  let remaining = digitFields.filter { $0.text?.count == 0 }
                  if remaining.count > 0 {
                      remaining[0].becomeFirstResponder()
                  } else {
                      digitFields.forEach { $0.resignFirstResponder() }
                  }
              }
          }
          

          结果:

          这取决于在数组中分组的文本字段。这可以在界面生成器中通过在 Outlet 配置屏幕中配置字段集合来实现:

          可以从最后一个选项卡项的视图控制器属性中访问

          注意,需要手动添加

          @IBOutlet var digitFields: [UITextField]!

          在您向视图控制器添加文本字段之前。

          代码行为总结

          • 视图控制器需要是 UITextFieldDelegate 才能允许它接收文本字段事件。
          • 在 viewDidLoad 函数中,数组中的每个文本字段都在 configureDigitField 方法中初始化
          • 在 viewWillAppear 方法中,数组中的第一个字段已准备好处理输入(即第一个条目将出现在其中)
          • configureDigitalField 函数将此视图控制器设置为从文本字段接收事件(每个文本字段都调用它们)
          • 它还设置了一个选择器,以便在文本字段编辑更改事件的结果上调用 textFieldDidChange 函数
          • textFieldDidChange 方法检查字段中文本的长度是否为1,如果是的话
          • 检查没有输入值的剩余文本字段
          • 获取剩余的第一个文本字段并将其设置为接收下一个输入
          • 如果没有剩余字段为空,则辞去其作为第一响应者的职位,因此在任何数字字段中都不会发生任何更多的按键操作

          【讨论】:

            【解决方案5】:

            Swift 4.x

            textField.addTarget(self, action: #selector(self.textFieldDidChange(textField:)), for: .editingChanged)
            

            @objc func textFieldDidChange(textField: UITextField)
            {
                let text = textField.text
                if text?.utf16.count == 1 {
                    switch textField {
                    case txtOtpNumber1:
                        txtOtpNumber2.becomeFirstResponder()
                    case txtOtpNumber2:
                        txtOtpNumber3.becomeFirstResponder()
                    case txtOtpNumber3:
                        txtOtpNumber4.becomeFirstResponder()
                    case txtOtpNumber4:
                        txtOtpNumber4.resignFirstResponder()
                    default:
                        break
                    }
                } else {
                    switch textField {
                    case txtOtpNumber4:
                        txtOtpNumber3.becomeFirstResponder()
                    case txtOtpNumber3:
                        txtOtpNumber2.becomeFirstResponder()
                    case txtOtpNumber2:
                        txtOtpNumber1.becomeFirstResponder()
                    case txtOtpNumber1:
                        txtOtpNumber1.resignFirstResponder()
                    default:
                        break
                    }
                }
            }
            

            PS。 Chetan's answer 更新为当前的 Swift。

            【讨论】:

              【解决方案6】:

              虽然这是一个老问题,但我只是遇到了它,我提出了更简单的解决方案。假设我们这样做是为了密码,所以每个框(UITextField)的最大长度是一个字符。

              - (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
                  if (![string isEqualToString:@""]) {
                      textField.text = string;
                      if ([textField isEqual:self.txtField1]) {
                          [self.txtField2 becomeFirstResponder];
                      }else if ([textField isEqual:self.txtField2]){
                          [self.txtField3 becomeFirstResponder];
                      }else if ([textField isEqual:self.txtField3]){
                          [self.txtField4 becomeFirstResponder];
                      }else{
                          [textField resignFirstResponder];
                      }
                      return NO;
                  }
                  return YES;
              }
              
              -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
                  if (textField.text.length > 0) {
                      textField.text = @"";
                  }
                  return YES;
              }
              

              【讨论】:

                猜你喜欢
                • 2018-01-23
                • 1970-01-01
                • 2019-12-02
                • 1970-01-01
                • 2012-03-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多