Как перемещаться по текстовым полям (кнопки "Далее" / "Готово" )

Как я могу перемещаться по всем моим текстовым полям с помощью кнопки "Далее" на клавиатуре iPhone?

Последнее текстовое поле должно закрыть клавиатуру.

Я установил IB кнопки (Next/Done), но теперь я застрял.

Я реализовал действие textFieldShouldReturn, но теперь кнопки Next и Done закрывают клавиатуру.

Ответ 1

В Cocoa для Mac OS X у вас есть следующая цепочка ответчиков, где вы можете запросить текстовое поле, какой элемент управления должен иметь фокус. Это то, что делает работу между текстовыми полями. Но поскольку устройства iOS не имеют клавиатуры, только касание, эта концепция не пережила переход на Cocoa Touch.

Это можно легко сделать в любом случае с двумя предположениями:

  • Все "tabbable" UITextField находятся на одном и том же родительском представлении.
  • Их "порядок табуляции" определяется свойством тега.

Предполагая это, вы можете переопределить 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 2.0

func textFieldShouldReturn(textField: UITextField) -> Bool {

let nextTage=textField.tag+1;
// Try to find next responder
let nextResponder=textField.superview?.viewWithTag(nextTage) as UIResponder!

if (nextResponder != nil){
    // Found next responder, so set it.
    nextResponder?.becomeFirstResponder()
}
else
{
    // Not found, so remove keyboard
    textField.resignFirstResponder()
}
return false // We do not want UITextField to insert line-breaks.
}

Если надписью текстового поля будет UITableViewCell, тогда следующий ответчик будет

let nextResponder=textField.superview?.superview?.superview?.viewWithTag(nextTage) as UIResponder!

Ответ 2

Есть гораздо более элегантное решение, которое взорвало меня в первый раз, когда я это увидел. Преимущества:

  • Ближе к реализации текстового поля OSX, где текстовое поле знает, куда следует идти дальше.
  • Не полагается на установку или использование тегов, которые являются уязвимыми для этого случая использования IMO
  • Может быть расширен для работы с элементами управления UITextField и UITextView - или с любым пользовательским интерфейсом управления клавиатурой
  • Не загромождает ваш контроллер представления с помощью кода делегата UITextField
  • Интегрируется хорошо с IB и может быть сконфигурирован с помощью знакомой опции-перетаскивания для подключения торговых точек.

Создайте подкласс UITextField, у которого есть свойство IBOutlet, называемое nextField. Здесь заголовок:

@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 измените UITextFields на использование класса SOTextField. Далее, также в IB, установите делегат для каждого из "SOTextFields" для "File Owner" (это правильно, где вы поместили код для метода делегата - textFieldShouldReturn). Красота этого дизайна заключается в том, что теперь вы можете просто щелкнуть правой кнопкой мыши на любом текстовом поле и назначить выход nextField на следующий объект SOTextField, которым вы хотите стать следующим ответчиком.

Assigning nextField in IB

Кроме того, вы можете делать такие классные вещи, как loop textFields, чтобы после того, как последний потерял фокус, первый снова получит фокус.

Это можно легко расширить, чтобы автоматически присваивать returnKeyType SOTextField a UIReturnKeyNext, если есть следующий назначенный Field - одна вещь, которую вручную настраивает.

Ответ 3

Вот мое решение для этой проблемы.

Чтобы решить эту проблему (и потому, что я ненавижу полагаться на теги, чтобы делать вещи), я решил добавить настраиваемое свойство к объекту 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, каждый из которых знает, кто следующий в строке.

Надеюсь, что это поможет.

Ответ 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).

Ответ 5

Быстрое расширение, которое применяет mxcl-ответ, чтобы сделать это особенно простым (адаптировано для Swift 2.3 от Traveler):

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

Ответ 6

Более последовательным и надежным способом является использование NextResponderTextField Вы можете полностью настроить его из конструктора интерфейса, не требуя установки делегата или используя view.tag.

Все, что вам нужно сделать, это

  • Задайте тип класса вашего UITextField как NextResponderTextField enter image description here
  • Затем установите розетку nextResponderField, чтобы указать на следующий ответчик, это может быть любой UITextField или любой подкласс UIResponder. Это может быть также UIButton, и библиотека достаточно умна, чтобы запускать событие TouchUpInside кнопки, только если она включена. enter image description hereenter image description here

Вот библиотека в действии:

enter image description here

Ответ 7

Мне нравятся решения OO, которые уже были предложены Anth0 и Answerbot. Тем не менее, я работал над быстрым и небольшим 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;
}
  • Я всегда возвращаю НЕТ, потому что я не хочу, чтобы был вставлен разрыв строки. Просто подумал, что я укажу, что с тех пор, как я вернусь, он автоматически выйдет из последующих полей или введет разрыв строки в моем TextView. Мне потребовалось немного времени, чтобы понять это.
  • activeField отслеживает активное поле в случае необходимости прокрутки, чтобы освободить поле от клавиатуры. Если у вас есть аналогичный код, убедитесь, что вы назначили activeField, прежде чем менять первого ответчика. Изменение первого ответчика является немедленным и немедленно вызовет событие KeyboardWasShown.

Ответ 8

Вот реализация табуляции с использованием категории в UIControl. Это решение имеет все преимущества методов от Michael и Anth0, но работает для всех UIControls, а не только UITextField s. Он также прекрасно работает с интерфейсом Builder и раскадровки.

Источник и пример приложения: Репозиторий GitHub для UIControlsWithTabbing

Использование:

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

Assigning nextControl in Interface Builder

Заголовок:

//
// 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

Ответ 9

После выхода из одного текстового поля вы вызываете [otherTextField статьFirstResponder], а следующее поле получает фокус.

На самом деле это может быть сложной проблемой, так как часто вы также хотите прокручивать экран или иным образом настраивать положение текстового поля, чтобы его можно было легко увидеть при редактировании. Просто убедитесь, что вы проводите много испытаний, прибегая к текстовым полям и выходите из них по-разному, а также оставляете на ранней стадии (всегда предоставляйте пользователю возможность отклонить клавиатуру вместо перехода в следующее поле, обычно с помощью "Готово" в панель навигации)

Ответ 10

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

Ответ 11

Очень простой способ отклонения клавиатуры при нажатии кнопки "Готово":

Создайте новый IBAction в заголовке

- (IBAction)textFieldDoneEditing:(id)sender;

В файле реализации (файл .m) добавьте следующий метод:

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

Затем, когда вы придете, чтобы связать IBAction с текстовым полем - ссылку на событие "Закончено на выход".

Ответ 12

Сначала установите ключ возврата клавиатуры в 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;
}

Ответ 13

Я удивлен тем, как много ответов здесь не понимают одну простую концепцию: переход через элементы управления в вашем приложении - это не то, что должны делать сами представления. Это задание контроллера, чтобы решить, какой элемент управления должен сделать следующим первым ответчиком.

Также большинство ответов применяются только для навигации вперед, но пользователи также могут захотеть вернуться назад.

Итак, вот что я придумал. Ваша форма должна управляться контроллером представления, а контроллеры просмотра являются частью цепочки ответчиков. Таким образом, вы совершенно свободны в реализации следующих методов:

#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 s), но вместо этого можете управлять логикой на уровне контроллера, где, допустим, подходящее место для этого.

Ответ 14

Я пробовал много кодов, и, наконец, это сработало для меня в Swift 3.0 Latest [March 2017]

Класс 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, где будет отображаться клавиша возврата клавиши Key, как Next, у вас также есть другие опции в качестве Join/Go и т.д., на основе вашего приложения измените значения.

Этот textFieldShouldReturn - это метод UITextFieldDelegate, и здесь мы имеем следующий выбор поля на основе приращения значения тега

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
 }

Ответ 15

Привет всем! этот

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

Ответ 16

Я добавил ответ 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 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

Ответ 17

Я попытался решить эту проблему, используя более сложный подход, основанный на назначении каждой ячейки (или UITextField) в UITableView уникальном значении тега, которое может быть получено позднее: activate-next-uitextfield-in-uitableview-ios

Надеюсь, это поможет!

Ответ 18

Я только что создал новый Pod, когда занимаюсь этим материалом GNTextFieldsCollectionManager. Он автоматически обрабатывает следующую/последнюю проблему TextField и очень прост в использовании:

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

Захватывает все текстовые поля, отсортированные по иерархии представлений (или по тегам), или вы можете указать свой собственный массив текстовых полей.

Ответ 19

Это сработало для меня в Xamarin.iOS/Monotouch. Измените кнопку клавиатуры на "Далее", передайте элемент управления на следующий 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.

Ответ 20

Я предпочитаю:

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

В файле NIB я привязываю текстовые поля в нужном порядке к этому массиву inputFields. После этого я делаю простой тест для индекса UITextField, который сообщает, что пользователь нажал return:

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

Ответ 21

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

Ответ 22

У меня было около 10+ UITextField в моей истории, и способ, которым я включил следующую функциональность, - создать массив UITextField и сделать следующий UITextField первымResponder. Здесь файл реализации:

#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

Ответ 23

Это простое решение в быстром, без использования тегов, никаких трюков с помощью раскадровки...

Просто используйте это расширение:

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

}

И назовите его так (например) с вашим делегатом текстового поля:

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

Ответ 24

в textFieldShouldReturn вы должны проверить, что текстовое поле, в котором вы находитесь в данный момент, не является последним, когда они нажимают кнопку "Далее", и если его не отклонять клавиатуру.

Ответ 25

Без использования тегов и без добавления свойства для 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];
                                                    }];

Ответ 26

Это старое сообщение, но имеет высокий рейтинг страницы, поэтому я буду отвечать своим решением.

У меня была аналогичная проблема, и я создал подкласс UIToolbar для управления следующей/предыдущей/выполняемой функциональностью в динамическом tableView с разделами: https://github.com/jday001/DataEntryToolbar

Вы устанавливаете панель инструментов в качестве inputAccessoryView своих текстовых полей и добавляете их в словарь. Это позволяет вам перебирать их вперед и назад, даже с динамическим контентом. Существуют методы делегатов, если вы хотите запускать свои собственные функции при навигации по тексту, но вам не нужно иметь дело с управлением любыми тегами или статусом первого ответчика.

В ссылке GitHub есть фрагменты кода и пример приложения, чтобы помочь с деталями реализации. Вам понадобится ваша собственная модель данных, чтобы отслеживать значения внутри полей.

Ответ 27

Я использую ответ Майкла Дж. Эммонса около года, отлично работает. Недавно я заметил, что вызов resignFirstResponder, а затем startFirstResponder сразу может привести к тому, что клавиатура "сработает", исчезнет, ​​а затем появится немедленно. Я немного изменил его версию, чтобы пропустить resignFirstResponder, если доступен следующийField.

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

}

Ответ 28

вы можете использовать библиотеку IQKeyboardManager для этого. он обрабатывает все, вам не нужна дополнительная настройка. IQKeyboardManager доступен через CocoaPods, для его установки просто добавьте следующую строку в ваш подфайл:

pod 'IQKeyboardManager'

или Просто перетащите каталог IQKeyBoardManager из демонстрационного проекта в свой проект. Это. вы можете найти каталог IQKeyBoardManager из https://github.com/hackiftekhar/IQKeyboardManager

Ответ 29

Вот версия Anth0 версии Swift 3. Я размещаю его здесь, чтобы помочь быстрым разработчикам, желающим воспользоваться его замечательным ответом! Я взял на себя смелость добавить тип возвращаемого ключа "Следующий", когда вы устанавливаете связанный объект.

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

Вот еще одно расширение, которое показывает возможность использования приведенного выше кода для циклического перехода по списку UITextFields.

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.

Ответ 30

Решение в 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
        }

    }