首页 文章

如何浏览文本字段(下一个/完成按钮)

提问于
浏览
464

如何使用iPhone键盘上的“下一步”按钮浏览所有文本字段?

最后一个文本字段应该关闭键盘 .

我已经设置了IB按钮(下一个/完成),但现在我被卡住了 .

我实现了textFieldShouldReturn操作,但现在Next和Done Buttons关闭了Keyboard .

30 回答

  • 2

    在Cocoa for Mac OS X中,您有下一个响应者链,您可以在其中询问文本字段接下来应该关注哪个控件 . 这就是使文本字段之间的标签工作的原因 . 但由于iOS设备没有键盘,只有触摸,这个概念还没有幸免于过渡到Cocoa Touch .

    无论如何,这可以轻松完成,有两个假设:

    • 所有"tabbable" UITextField s位于同一父视图中 .

    • 他们的"tab-order"由tag属性定义 .

    假设你可以覆盖textFieldShouldReturn:如下:

    -(BOOL)textFieldShouldReturn:(UITextField*)textField
    {
      NSInteger nextTag = textField.tag + 1;
      // Try to find next responder
      UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
      if (nextResponder) {
        // Found next responder, so set it.
        [nextResponder becomeFirstResponder];
      } else {
        // Not found, so remove keyboard.
        [textField resignFirstResponder];
      }
      return NO; // We do not want UITextField to insert line-breaks.
    }
    

    添加更多代码,也可以忽略这些假设 .

    Swift 4.0

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        let nextTag = textField.tag + 1
        // Try to find next responder
        let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder!
    
        if nextResponder != nil {
            // Found next responder, so set it
            nextResponder?.becomeFirstResponder()
        } else {
            // Not found, so remove keyboard
            textField.resignFirstResponder()
        }
    
        return false
    }
    

    If the superview of the text field will be a UITableViewCell then next responder will be

    let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
    
  • 169

    有一个更优雅的解决方案,在我第一次看到它时就把我吹走了 . 优点:

    • 更接近OSX文本字段实现,其中文本字段知道下一个焦点的位置

    • 不依赖于设置或使用标签 - 这对于此用例来说是IMO脆弱的

    • 可以扩展为与 UITextFieldUITextView 控件一起使用 - 或任何键盘输入UI控件

    • 不会使用样板文件UITextField委托代码来混淆视图控制器

    • 与IB很好地集成,可以通过熟悉的选项 - 拖放来配置连接插座 .

    创建一个UITextField子类,它具有名为nextField的 IBOutlet 属性 . 这是 Headers :

    @interface SOTextField : UITextField
    
    @property (weak, nonatomic) IBOutlet UITextField *nextField; 
    
    @end
    

    这是实施:

    @implementation SOTextField
    
    @end
    

    在视图控制器中,您将创建 -textFieldShouldReturn: 委托方法:

    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        if ([textField isKindOfClass:[SOTextField class]]) {
            UITextField *nextField = [(SOTextField *)textField nextField];
    
            if (nextField) {
                dispatch_async(dispatch_get_current_queue(), ^{
                    [nextField becomeFirstResponder];
                });
            }
            else {
                [textField resignFirstResponder];
            }
        }
    
        return YES;
    }
    

    在IB中,更改您的UITextField以使用 SOTextField 类 . 接下来,同样在IB中,为每个'SOTextFields'设置委托给'File''所有者'(这是您放置委托方法代码的地方 - textFieldShouldReturn) . 这种设计的优点在于,现在您只需右键单击任何textField,并将nextField出口分配给您希望成为下一个响应者的下一个 SOTextField 对象 .

    Assigning nextField in IB

    此外,你可以做很酷的事情,比如循环textFields,这样在最后一个失去焦点后,第一个会再次获得焦点 .

    如果分配了nextField,则可以轻松扩展为自动将

    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        if ([textField isKindOfClass:[SOTextField class]]) {
            UITextField *nextField = [(SOTextField *)textField nextField];
    
            if (nextField) {
                dispatch_async(dispatch_get_current_queue(), ^{
                    [nextField becomeFirstResponder];
                });
            }
            else {
                [textField resignFirstResponder];
            }
        }
    
        return YES;
    }
    

    returnKeyType 分配给 UIReturnKeyNext - 少一点手动配置 .

  • 2

    这是我解决这个问题的方法 .

    为了解决这个问题(因为我讨厌依赖标签来做东西),我决定在UITextField对象中添加一个自定义属性 . 换句话说,我在UITextField上创建了一个类别,如下所示:

    UITextField+Extended.h

    @interface UITextField (Extended)
    
    @property(retain, nonatomic)UITextField* nextTextField;
    
    @end
    

    UITextField+Extended.m

    #import "UITextField+Extended.h"
    #import <objc/runtime.h>
    
    static char defaultHashKey;
    
    @implementation UITextField (Extended)
    
    - (UITextField*) nextTextField { 
        return objc_getAssociatedObject(self, &defaultHashKey); 
    }
    
    - (void) setNextTextField:(UITextField *)nextTextField{
        objc_setAssociatedObject(self, &defaultHashKey, nextTextField, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    }
    
    @end
    

    现在,这是我如何使用它:

    UITextField *textField1 = ...init your textfield
    UITextField *textField2 = ...init your textfield
    UITextField *textField3 = ...init your textfield
    
    textField1.nextTextField = textField2;
    textField2.nextTextField = textField3;
    textField3.nextTextField = nil;
    

    并实现textFieldShouldReturn方法:

    - (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
    
        UITextField *next = theTextField.nextTextField;
        if (next) {
            [next becomeFirstResponder];
        } else {
            [theTextField resignFirstResponder];
        }
    
        return NO; 
    }
    

    我现在有一个UITextField的链接列表,每个人都知道谁在下一行 .

    希望它会有所帮助 .

  • 2

    我刚刚在处理这些东西时创建了新的Pod GNTextFieldsCollectionManager . 它会自动处理下一个/最后一个textField问题,并且非常易于使用:

    [[GNTextFieldsCollectionManager alloc] initWithView:self.view];
    

    抓取按视图层次结构(或标记)显示的所有文本字段,或者您可以指定自己的textFields数组 .

  • 4

    这是一个没有代表团的人:

    tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
    tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
    

    ObjC:

    [tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
    [tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
    

    使用(主要是未知的) UIControlEventEditingDidEndOnExit UITextField 动作 .

    您还可以轻松地将其连接到故事板中,因此不需要委托或代码 .

    编辑:实际上我无法弄清楚如何在故事板中将其连接起来 . becomeFirstResponder 似乎不是这个控制事件的提供动作,这是一个遗憾 . 仍然,您可以将所有文本字段挂钩到ViewController中的单个操作,然后根据发件人确定哪个textField为 becomeFirstResponder (尽管它不像上面的程序化解决方案那样优雅,所以IMO使用 viewDidLoad 中的上述代码执行此操作) .

  • 2

    一个快速扩展,应用mxcl的答案,使这特别容易(适应旅行者swift 2.3):

    extension UITextField {
        class func connectFields(fields:[UITextField]) -> Void {
            guard let last = fields.last else {
                return
            }
            for i in 0 ..< fields.count - 1 {
                fields[i].returnKeyType = .Next
                fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
            }
            last.returnKeyType = .Done
            last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
        }
    }
    

    它易于使用:

    UITextField.connectFields([field1, field2, field3])
    

    对于除最后一个字段之外的所有字段,扩展名将返回按钮设置为“下一个”,对于最后一个字段,将“返回”设置为“完成”,并在点击这些字段时切换焦点/关闭键盘 .

    Swift < 2.3

    extension UITextField {
        class func connectFields(fields:[UITextField]) -> Void {
            guard let last = fields.last else {
                return
            }
            for var i = 0; i < fields.count - 1; i += 1 {
                fields[i].returnKeyType = .Next
                fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
            }
            last.returnKeyType = .Done
            last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
        }
    }
    

    SWIFT 3: 像这样使用 -

    UITextField.connectFields(fields: [field1, field2])
    
    Extension:
        extension UITextField {
            class func connectFields(fields:[UITextField]) -> Void {
                guard let last = fields.last else {
                    return
                }
                for i in 0 ..< fields.count - 1 {
                    fields[i].returnKeyType = .next
                    fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
                }
                last.returnKeyType = .go
                last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
            }
        }
    
  • 2

    更一致和更健壮的方法是使用NextResponderTextField您可以完全从界面构建器配置它,而无需设置委托或使用 view.tag .

    你需要做的就是

    • UITextField 的 class 类型设为 NextResponderTextField
      enter image description here

    • 然后将 nextResponderField 的出口设置为指向下一个响应者,它可以是任何 UITextField 或任何 UIResponder 子类 . 它也可以是一个UIButton,并且该库足够智能,只有在启用时才会触发按钮的 TouchUpInside 事件 .
      enter image description here

    enter image description here

    这是图书馆的行动:

    enter image description here

  • 6

    我喜欢Anth0和Answerbot已经提出过的OO解决方案 . 但是,我正在开发一个快速小巧的POC,所以我不想让子类和类别混乱 .

    另一个简单的解决方案是创建一个NSArray字段,并在按下下一个字段时查找下一个字段 . 不是OO解决方案,但快速,简单且易于实施 . 此外,您可以一目了然地查看和修改订购 .

    这是我的代码(基于此线程中的其他答案):

    @property (nonatomic) NSArray *fieldArray;
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
    }
    
    - (BOOL) textFieldShouldReturn:(UITextField *) textField {
        BOOL didResign = [textField resignFirstResponder];
        if (!didResign) return NO;
    
        NSUInteger index = [self.fieldArray indexOfObject:textField];
        if (index == NSNotFound || index + 1 == fieldArray.count) return NO;
    
        id nextField = [fieldArray objectAtIndex:index + 1];
        activeField = nextField;
        [nextField becomeFirstResponder];
    
        return NO;
    }
    
    • 我总是返回NO,因为我没有指出,因为当我返回YES时它将自动退出后续字段或在我的TextView中插入换行符 . 我花了一点时间才弄明白 .

    • activeField会跟踪活动字段,以防需要滚动以从键盘中取消显示字段 . 如果您有类似的代码,请确保在更改第一个响应者之前分配activeField . 立即更改第一响应者并立即触发KeyboardWasShown事件 .

  • 78

    这是使用UIControl上的类别进行Tab键的实现 . 这个解决方案具有Michael和Anth0方法的所有优点,但适用于所有UIControl,而不仅仅是 UITextField . 它还可以与Interface Builder和故事板无缝协作 .

    来源和示例应用:GitHub repository for UIControlsWithTabbing

    用法:

    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        [textField transferFirstResponderToNextControl];
        return NO;
    }
    

    Assigning nextControl in Interface Builder

    Headers :

    //
    // UIControl+NextControl.h
    // UIControlsWithTabbing
    //
    
    #import <UIKit/UIKit.h>
    
    @interface UIControl (NextControl)
    
    @property (nonatomic, weak) IBOutlet UIControl *nextControl;
    
    - (BOOL)transferFirstResponderToNextControl;
    
    @end
    

    执行:

    #import "UIControl+NextControl.h"
    #import <objc/runtime.h>
    
    static char defaultHashKey;
    
    @implementation UIControl (NextControl)
    
    - (UIControl *)nextControl
    {
        return objc_getAssociatedObject(self, &defaultHashKey);
    }
    
    - (void)setNextControl:(UIControl *)nextControl
    {
        objc_setAssociatedObject(self, &defaultHashKey, nextControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (BOOL)transferFirstResponderToNextControl
    {
        if (self.nextControl)
        {
            [self.nextControl becomeFirstResponder];
    
            return YES;
        }
    
        [self resignFirstResponder];
    
        return NO;
    }
    
    @end
    
  • 3

    退出一个文本字段后,调用[otherTextField becomeFirstResponder],下一个字段获得焦点 .

    这实际上可能是一个棘手的问题,因为您通常还需要滚动屏幕或以其他方式调整文本字段的位置,以便在编辑时很容易看到 . 只需确保以不同的方式进出文本字段并进行大量测试,并提前离开(总是让用户选择关闭键盘而不是去下一个字段,通常使用“完成”导航栏)

  • 3
    -(BOOL)textFieldShouldReturn:(UITextField *)textField
    {
       [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
       return YES;
    }
    
  • 3

    我尝试了很多代码,最后,这对我有用_11244382_

    ViewController 类应继承 UITextFieldDelegate 以使此代码正常工作 .

    class ViewController: UIViewController,UITextFieldDelegate
    

    添加带有正确标记号的文本字段,此标记号用于根据分配给它的增量标记号将控件转移到适当的文本字段 .

    override func viewDidLoad() {
        userNameTextField.delegate = self
        userNameTextField.tag = 0
        userNameTextField.returnKeyType = UIReturnKeyType.next
        passwordTextField.delegate = self
        passwordTextField.tag = 1
        passwordTextField.returnKeyType = UIReturnKeyType.go
    }
    

    在上面的代码中, returnKeyType = UIReturnKeyType.next where将使键盘返回键显示为 Next 您还有其他选项 Join/Go 等,根据您的应用程序更改值 .

    这个 textFieldShouldReturn 是一个UITextFieldDelegate控制的方法,这里我们根据Tag值增量进行下一个字段选择

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
            nextField.becomeFirstResponder()
        } else {
            textField.resignFirstResponder()
            return true;
        }
        return false
     }
    
  • 7

    按下“完成”按钮时,解除键盘的一种非常简单的方法是:

    在 Headers 中创建一个新的IBAction

    - (IBAction)textFieldDoneEditing:(id)sender;
    

    在实现文件(.m文件)中添加以下方法:

    - (IBAction)textFieldDoneEditing:(id)sender 
    { 
      [sender resignFirstResponder];
    }
    

    然后,当您将IBAction链接到文本字段时 - 链接到“退出时结束”事件 .

  • 2

    我很惊讶这里有多少答案无法理解一个简单的概念:浏览应用程序中的控件并不是视图本身应该做的事情 . 确定下一个第一响应者的控制权是 controller 的工作 .

    此外,大多数答案仅适用于向前导航,但用户可能也想要倒退 .

    所以这就是我想出来的 . 您的表单应由视图控制器管理,视图控制器是响应程序链的一部分 . 所以你可以完全自由地实现以下方法:

    #pragma mark - Key Commands
    
    - (NSArray *)keyCommands
    {
        static NSArray *commands;
    
        static dispatch_once_t once;
        dispatch_once(&once, ^{
            UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(tabForward:)];
            UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];
    
            commands = @[forward, backward];
        });
    
        return commands;
    }
    
    - (void)tabForward:(UIKeyCommand *)command
    {
        NSArray *const controls = self.controls;
        UIResponder *firstResponder = nil;
    
        for (UIResponder *const responder in controls) {
            if (firstResponder != nil && responder.canBecomeFirstResponder) {
                [responder becomeFirstResponder]; return;
            }
            else if (responder.isFirstResponder) {
                firstResponder = responder;
            }
        }
    
        [controls.firstObject becomeFirstResponder];
    }
    
    - (void)tabBackward:(UIKeyCommand *)command
    {
        NSArray *const controls = self.controls;
        UIResponder *firstResponder = nil;
    
        for (UIResponder *const responder in controls.reverseObjectEnumerator) {
            if (firstResponder != nil && responder.canBecomeFirstResponder) {
                [responder becomeFirstResponder]; return;
            }
            else if (responder.isFirstResponder) {
                firstResponder = responder;
            }
        }
    
        [controls.lastObject becomeFirstResponder];
    }
    

    可以应用用于预先滚动屏幕外响应者的附加逻辑 .

    这种方法的另一个优点是你不需要子类化你可能想要显示的所有类型的控件(比如 UITextField ),而是可以在控制器级别管理逻辑,其中,说实话,是正确的地方所以 .

  • 43

    首先在xib中设置键盘返回键,否则你可以在 viewdidload 中编写代码:

    passWord.returnKeyType = UIReturnKeyNext;
    
    -(BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        if(textField == eMail) {
            [textField resignFirstResponder];
            [userName becomeFirstResponder];
        }
        if (textField==userName) {
            [textField resignFirstResponder];
            [passWord becomeFirstResponder];
        }
        if (textField==passWord) {
            [textField resignFirstResponder];
            [country becomeFirstResponder];
        }
        if (textField==country) {
            [textField resignFirstResponder];
        }
        return YES;
    }
    
  • 3

    我已经添加了PeyloW的答案,以防你想要实现上一个/下一个按钮功能:

    - (IBAction)moveThroughTextFields:(UIBarButtonItem *)sender 
    {
        NSInteger nextTag;
        UITextView *currentTextField = [self.view findFirstResponderAndReturn];
    
        if (currentTextField != nil) {
            // I assigned tags to the buttons.  0 represent prev & 1 represents next
            if (sender.tag == 0) {
                nextTag = currentTextField.tag - 1;
    
            } else if (sender.tag == 1) {
                nextTag = currentTextField.tag + 1;
            }
        }
        // Try to find next responder
        UIResponder* nextResponder = [self.view viewWithTag:nextTag];
        if (nextResponder) {
            // Found next responder, so set it.
            // I added the resign here in case there's different keyboards in place.
            [currentTextField resignFirstResponder];
            [nextResponder becomeFirstResponder];
        } else {
            // Not found, so remove keyboard.
            [currentTextField resignFirstResponder];
    
        }
    }
    

    你把UIView子类化的地方是这样的:

    @implementation UIView (FindAndReturnFirstResponder)
    - (UITextView *)findFirstResponderAndReturn
    {
        for (UITextView *subView in self.subviews) {
            if (subView.isFirstResponder){
                return subView;
            }
        }
        return nil;
    }
    @end
    
  • 9

    大家好,请看this one

    - (void)nextPrevious:(id)sender
    {
    
      UIView *responder = [self.view findFirstResponder];   
    
      if (nil == responder || ![responder isKindOfClass:[GroupTextField class]]) {
        return;
      }
    
      switch([(UISegmentedControl *)sender selectedSegmentIndex]) {
        case 0:
          // previous
          if (nil != ((GroupTextField *)responder).previousControl) {
            [((GroupTextField *)responder).previousControl becomeFirstResponder];
            DebugLog(@"currentControl: %i previousControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).previousControl.tag);
          }
          break;
        case 1:
          // next
          if (nil != ((GroupTextField *)responder).nextControl) {
            [((GroupTextField *)responder).nextControl becomeFirstResponder];
            DebugLog(@"currentControl: %i nextControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).nextControl.tag);
          }     
          break;    
      }
    }
    
  • 3

    我尝试使用更复杂的方法来解决这个问题,这种方法基于在_1124404中分配每个单元格(或 UITextField ),这是一个可以在以后检索的唯一标记值:activate-next-uitextfield-in-uitableview-ios

    我希望这有帮助!

  • 11

    Swift 3.1中的解决方案,在连接文本字段后,IBOutlets在viewDidLoad中设置文本字段委托,然后在textFieldShouldReturn中导航您的操作

    class YourViewController: UIViewController,UITextFieldDelegate {
    
            @IBOutlet weak var passwordTextField: UITextField!
            @IBOutlet weak var phoneTextField: UITextField!
    
            override func viewDidLoad() {
                super.viewDidLoad()
                self.passwordTextField.delegate = self
                self.phoneTextField.delegate = self
                // Set your return type
                self.phoneTextField.returnKeyType = .next
                self.passwordTextField.returnKeyType = .done
            }
    
            func textFieldShouldReturn(_ textField: UITextField) -> Bool{
                if textField == self.phoneTextField {
                    self.passwordTextField.becomeFirstResponder()
                }else if textField == self.passwordTextField{
                    // Call login api
                    self.login()
                }
                return true
            }
    
        }
    
  • 14

    我更喜欢:

    @interface MyViewController : UIViewController
    @property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
    @end
    

    在NIB文件中,我将textFields以所需顺序挂钩到此inputFields数组中 . 之后,我对UITextField的索引进行了简单测试,该索引报告用户点击了返回:

    // for UITextField
    -(BOOL)textFieldShouldReturn:(UITextField*)textField {
        NSUInteger index = [_inputFields indexOfObject:textField];
        index++;
        if (index < _inputFields.count) {
            UIView *v = [_inputFields objectAtIndex:index];
            [v becomeFirstResponder];
        }
        return NO;
    }
    
    // for UITextView
    -(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
        if ([@"\n" isEqualToString:text]) {
            NSUInteger index = [_inputFields indexOfObject:textView];
            index++;
            if (index < _inputFields.count) {
                UIView *v = [_inputFields objectAtIndex:index];
                [v becomeFirstResponder];
            } else {
                [self.view endEditing:YES];
            }
            return NO;
        }
        return YES;
    }
    
  • 9
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        txt_Input = [[ UITextField alloc] initWithFrame:CGRectMake(0, 10, 150, 30)];
        txt_Input.tag = indexPath.row+1;
        [self.array_Textfields addObject:txt_Input]; // Initialize mutable array in ViewDidLoad
    }
    
    -(BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    
        int tag = ( int) textField.tag ;
        UITextField * txt = [  self.array_Textfields objectAtIndex:tag ] ;
        [ txt becomeFirstResponder] ;
        return YES ;
    }
    
  • 75

    我的故事板上有大约10个UITextField,我启用下一个功能的方法是创建一个UITextField数组,并使下一个UITextField成为第一个响应者 . 这是实现文件:

    #import "RegistrationTableViewController.h"
    
    @interface RegistrationTableViewController ()
    @property (weak, nonatomic) IBOutlet UITextField *fullNameTextField;
    @property (weak, nonatomic) IBOutlet UITextField *addressTextField;
    @property (weak, nonatomic) IBOutlet UITextField *address2TextField;
    @property (weak, nonatomic) IBOutlet UITextField *cityTextField;
    @property (weak, nonatomic) IBOutlet UITextField *zipCodeTextField;
    @property (weak, nonatomic) IBOutlet UITextField *urlTextField;
    @property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
    @property (weak, nonatomic) IBOutlet UITextField *emailTextField;
    @property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
    @property (weak, nonatomic) IBOutlet UITextField *confirmPWTextField;
    
    @end
    NSArray *uiTextFieldArray;
    @implementation RegistrationTableViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"view did load");
        uiTextFieldArray = @[self.fullNameTextField,self.addressTextField,self.address2TextField,self.cityTextField,self.zipCodeTextField,self.urlTextField,self.usernameTextField,self.emailTextField,self.passwordTextField,self.confirmPWTextField];
        for(UITextField *myField in uiTextFieldArray){
            myField.delegate = self;
        }
    
    
    }
    -(BOOL)textFieldShouldReturn:(UITextField *)textField{
        long index = [uiTextFieldArray indexOfObject:textField];
        NSLog(@"%ld",index);
        if(index < (uiTextFieldArray.count - 1)){
            [uiTextFieldArray[++index] becomeFirstResponder];
        }else{
            [uiTextFieldArray[index] resignFirstResponder];
        }
        return YES;
    }
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
  • 9

    这在Xamarin.iOS / Monotouch中适用于我 . 将键盘按钮更改为Next,将控件传递给下一个UITextField,并在最后一个UITextField之后隐藏键盘 .

    private void SetShouldReturnDelegates(IEnumerable<UIView> subViewsToScout )
    {
      foreach (var item in subViewsToScout.Where(item => item.GetType() == typeof (UITextField)))
      {
        (item as UITextField).ReturnKeyType = UIReturnKeyType.Next;
        (item as UITextField).ShouldReturn += (textField) =>
        {
            nint nextTag = textField.Tag + 1;
            var nextResponder = textField.Superview.ViewWithTag(nextTag);
            if (null != nextResponder)
                nextResponder.BecomeFirstResponder();
            else
                textField.Superview.EndEditing(true); 
                //You could also use textField.ResignFirstResponder(); 
    
            return false; // We do not want UITextField to insert line-breaks.
        };
      }
    }
    

    ViewDidLoad 内你将拥有:

    如果您的TextFields现在没有设置标签:

    txtField1.Tag = 0;
    txtField2.Tag = 1;
    txtField3.Tag = 2;
    //...
    

    只是电话

    SetShouldReturnDelegates(yourViewWithTxtFields.Subviews.ToList());
    //If you are not sure of which view contains your fields you can also call it in a safer way:
    SetShouldReturnDelegates(txtField1.Superview.Subviews.ToList());
    //You can also reuse the same method with different containerViews in case your UITextField are under different views.
    
  • 4

    这是一个简单的快速解决方案,没有标签使用,没有故事板技巧......

    只需使用此扩展程序:

    extension UITextField{
    
        func nextTextFieldField() -> UITextField?{
            //field to return
            var returnField : UITextField?
            if self.superview != nil{
                //for each view in superview
                for (_, view) in self.superview!.subviews.enumerate(){
                    //if subview is a text's field
                    if view.isKindOfClass(UITextField){
                        //cast curent view as text field
                        let currentTextField = view as! UITextField
                        //if text field is after the current one
                        if currentTextField.frame.origin.y > self.frame.origin.y{
                            //if there is no text field to return already
                            if returnField == nil {
                                //set as default return
                                returnField = currentTextField
                            }
                                //else if this this less far than the other
                            else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
                                //this is the field to return
                                returnField = currentTextField
                            }
                        }
                    }
                }
            }
            //end of the mdethod
            return returnField
        }
    
    }
    

    并使用您的textfield委托调用它(例如):

    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        textField.nextTextFieldField()?.becomeFirstResponder()
        return true
    }
    
  • 4

    在textFieldShouldReturn中,你应该检查你当前所在的文本字段是不是最后一个,当他们点击下一个,如果它不要关闭键盘..

  • 552

    这是一个老帖子,但页面排名很高,所以我会使用我的解决方案 .

    我遇到了类似的问题,并最终创建了一个 UIToolbar 的子类来管理动态tableView中的下一个/上一个/完成的功能,其中包含以下部分:https://github.com/jday001/DataEntryToolbar

    您将工具栏设置为文本字段的inputAccessoryView并将其添加到其字典中 . 这使您可以向前和向后循环,即使是动态内容也是如此 . 如果要在textField导航发生时触发自己的功能,则有委托方法,但您不必处理管理任何标记或第一响应者状态 .

    GitHub链接中有代码片段和示例应用程序,以帮助实现详细信息 . 您将需要自己的数据模型来跟踪字段内的值 .

  • 4

    如果没有使用标签并且没有为nextField / nextTextField添加属性,您可以尝试使用它来模拟TAB,其中“testInput”是您当前的活动字段:

    if ([textInput isFirstResponder])
        [textInput.superview.subviews enumerateObjectsAtIndexes:
         [NSIndexSet indexSetWithIndexesInRange:
          NSMakeRange([textInput.superview.subviews indexOfObject:textInput]+1,
                      [textInput.superview.subviews count]-[textInput.superview.subviews indexOfObject:textInput]-1)]
                                                        options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                            *stop = !obj.hidden && [obj becomeFirstResponder];
                                                        }];
    if ([textInput isFirstResponder])
        [textInput.superview.subviews enumerateObjectsAtIndexes:
         [NSIndexSet indexSetWithIndexesInRange:
          NSMakeRange(0,
                      [textInput.superview.subviews indexOfObject:textInput])]
                                                        options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                            *stop = !obj.hidden && [obj becomeFirstResponder];
                                                        }];
    
  • 7

    我一直在使用Michael G. Emmons的答案大约一年,效果很好 . 我最近注意到,调用resignFirstResponder然后立即调用FirstFirstResponder会导致键盘“出现故障”,消失然后立即出现 . 如果nextField可用,我稍微更改了他的版本以跳过resignFirstResponder .

    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    { 
    
        if ([textField isKindOfClass:[NRTextField class]])
        {
            NRTextField *nText = (NRTextField*)textField;
            if ([nText nextField] != nil){
                dispatch_async(dispatch_get_main_queue(),
                               ^ { [[nText nextField] becomeFirstResponder]; });
    
            }
            else{
                [textField resignFirstResponder];
            }
        }
        else{
            [textField resignFirstResponder];
        }
    
        return true;
    
    }
    
  • 25

    您可以使用IQKeyboardManager库来执行此操作 . 它处理所有事情,你不需要任何额外的setup.IQKeyboardManager可以通过CocoaPods,安装它只需将以下行添加到你的Podfile:

    pod 'IQKeyboardManager'
    

    或者只是将IQKeyBoardManager目录从演示项目拖放到您的项目中 . 而已 . 你可以在https://github.com/hackiftekhar/IQKeyboardManager找到IQKeyBoardManager目录

  • 4

    这是一个Swift 3版本的 Anth0 's answer. I' m在这里张贴,以帮助任何快速的开发人员想要利用他的好答案!当您设置关联对象时,我冒昧地添加了返回键类型"Next" .

    extension UITextField {
    
      @nonobjc static var NextHashKey: UniChar = 0
    
      var nextTextField: UITextField? {
        get {
          return objc_getAssociatedObject(self, 
            &UITextField.NextHashKey) as? UITextField
        }
        set(next) {
         self.returnKeyType = UIReturnKeyType.next
         objc_setAssociatedObject(self,
          &UITextField.NextHashKey,next,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
      }
    }
    

    这是另一个扩展,显示了使用上面的代码循环遍历UITextField列表的可能性 .

    extension UIViewController: UITextFieldDelegate {
     public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
       guard let next = textField.nextTextField else {
         textField.resignFirstResponder()
         return true
       }
    
        next.becomeFirstResponder()
        return false
      }
    }
    

    然后在你的ViewController或任何地方,你可以像这样设置你的文本域...

    @IBOutlet fileprivate weak var textfield1: UITextField!
    @IBOutlet fileprivate weak var textfield2: UITextField!
    @IBOutlet fileprivate weak var textfield3: UITextField!
    
    ...
    
    [textfield1, textfield2, textfield3].forEach{ $0?.delegate = self }
    
    textfield1.nextTextField = textfield2
    textfield2.nextTextField = textfield3
    // We don't assign a nextTextField to textfield3 because we want 
    // textfield3 to be the last one and resignFirstResponder when 
    // the return button on the soft keyboard is tapped.
    

相关问题