Programing

텍스트 필드를 탐색하는 방법 (다음 / 완료 단추)

lottogame 2020. 2. 14. 23:22
반응형

텍스트 필드를 탐색하는 방법 (다음 / 완료 단추)


iPhone 키보드의 "다음"버튼으로 모든 텍스트 필드를 탐색하려면 어떻게해야합니까?

마지막 텍스트 필드는 키보드를 닫아야합니다.

IB 버튼 (다음 / 완료)을 설정했지만 이제 막혔습니다.

textFieldShouldReturn 액션을 구현했지만 이제 다음 및 완료 버튼으로 키보드가 닫힙니다.


Mac OS X 용 Cocoa에는 다음 응답기 체인이 있으며, 여기에서 텍스트 필드에 어떤 제어에 초점을 두어야하는지 물어볼 수 있습니다. 이것이 텍스트 필드 사이의 탭을 작동시키는 것입니다. 그러나 iOS 기기에는 키보드가없고 터치 만 있기 때문에이 개념은 Cocoa Touch 로의 전환에서 살아남지 못했습니다.

어쨌든 두 가지 가정으로 쉽게 수행 할 수 있습니다.

  1. 모든 "tabbable" UITextField은 동일한 상위 뷰에 있습니다.
  2. "탭 순서"는 태그 속성으로 정의됩니다.

이것을 가정하면 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.
}

더 많은 코드를 추가하면 가정도 무시할 수 있습니다.

스위프트 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
}

텍스트 필드의 수퍼 뷰가 UITableViewCell이면 다음 응답자는

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

많이 나는 그것을 처음봤을 때 저를 멀리 날려 더 우아한 해결책은. 혜택:

  • 텍스트 필드가 다음에 어디로 가야하는지 알고있는 OSX 텍스트 필드 구현에 더 가깝습니다.
  • 태그 사용 또는 태그 사용에 의존하지 않음-이 사용 사례에서 취약한 IMO
  • 컨트롤 UITextFieldUITextView키보드 입력 UI 컨트롤 모두에서 작동하도록 확장 가능
  • 상용구 UITextField 델리게이트 코드로 뷰 컨트롤러를 어지럽히 지 않습니다.
  • IB와 완벽하게 통합되며 친숙한 옵션 끌어서 놓기를 통해 구성하여 콘센트를 연결할 수 있습니다.

IBOutletnextField라는 속성 이있는 UITextField 서브 클래스를 작성하십시오 . 헤더는 다음과 같습니다.

@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에서 SOTextField클래스 를 사용하도록 UITextField를 변경하십시오 . 다음으로 IB에서도 각 'SOTextFields'에 대한 대리자를 'File 's Owner'(대리자 메서드-textFieldShouldReturn에 대한 코드를 넣는 위치)로 설정합니다. 이 디자인의 장점은 이제 모든 textField를 마우스 오른쪽 단추로 클릭하고 nextField 콘센트를 SOTextField다음 응답자가 될 다음 객체에 할당 할 수 있다는 것입니다.

IB에서 nextField 할당

또한 텍스트 필드 루프와 같은 멋진 작업을 수행하여 마지막 필드가 포커스를 잃은 후 첫 번째 필드가 다시 포커스를받을 수 있습니다.

이것은 쉽게 자동으로 할당하도록 확장 할 수 returnKeyType의를 SOTextFieldA를 UIReturnKeyNext한 적은 일이 수동으로 구성 - nextField 할당이있는 경우.


대표단이없는 사람은 다음과 같습니다.

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에서 하나의 액션 becomeFirstResponder으로 연결하여 보낸 사람 기준으로 텍스트 필드를 결정할 수 있습니다 (그러나 위의 프로그래밍 솔루션만큼 우아하지 않으므로 IMO는 위의 코드로 수행합니다 viewDidLoad).


이 문제에 대한 해결책은 다음과 같습니다.

이 문제를 해결하기 위해 (그리고 태그를 사용하여 작업하는 것을 싫어하기 때문에) 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의 연결된 목록이 생겼습니다. 각 목록은 누가 다음 줄에 있는지 알고 있습니다.

도움이 되길 바랍니다.


mxcl의 답변을 적용하여 특히 쉽게 만들 수있는 빠른 확장 기능 (Traveler의 신속한 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])

확장 프로그램은 마지막 필드를 제외한 모든 필드에 대해 리턴 버튼을 "다음"으로 설정하고 마지막 필드에 대해서는 "완료"로 설정하고 탭을 누르면 포커스를 이동 / 닫습니다.

스위프트 <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)
    }
}

스위프트 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)
        }
    }

보다 일관되고 강력한 방법은 NextResponderTextField 를 사용 하는 것 view.tag입니다. 델리게이트를 설정하거나 사용할 필요없이 인터페이스 빌더에서 완전히 구성 할 수 있습니다 .

당신이해야 할 일은

  1. 당신의 클래스 유형을 설정 UITextFieldNextResponderTextField 여기에 이미지 설명을 입력하십시오
  2. 그런 다음의 출구를 설정 nextResponderField그것이 무엇이든 할 수있는 다음 응답을 가리 키도록 UITextField또는 UIResponder서브 클래스입니다. 또한 UIButton 일 수 있으며 라이브러리는 TouchUpInside활성화 된 경우에만 버튼 이벤트 를 트리거 할 수있을 정도로 똑똑 합니다.여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

작동중인 라이브러리는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


나는 Anth0과 Answerbot이 이미 제안한 OO 솔루션을 좋아합니다. 그러나 나는 빠르고 작은 POC를 연구하고 있었기 때문에 서브 클래스와 범주로 물건을 어지럽히고 싶지 않았습니다.

또 다른 간단한 해결책은 NSArray 필드를 만들고 next를 누를 때 다음 필드를 찾는 것입니다. 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 이벤트가 시작됩니다.

다음은 UIControl에서 카테고리를 사용하여 탭하는 구현입니다. 이 솔루션은 Michael과 Anth0의 메소드의 모든 장점을 가지고 있지만 UITextFields 뿐만 아니라 모든 UIControl에서 작동합니다 . 또한 Interface Builder 및 스토리 보드와 완벽하게 작동합니다.

소스 및 샘플 앱 : UIControlsWithTabbing 용 GitHub 저장소

용법:

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

인터페이스 빌더에서 nextControl 할당

머리글:

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

많은 코드를 시도해 보니 마지막으로 Swift 3.0 Latest [2017 년 3 월] 에서 효과가있었습니다 .

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키패드 반환 키를 표시 하는 위치는 어디 입니까?NextJoin/Go

이것은 textFieldShouldReturnUITextFieldDelegate 제어 방법이며 여기에서 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
 }

하나의 텍스트 필드를 종료 한 후 [otherTextField가 FirstResponder]를 호출하면 다음 필드에 포커스가 있습니다.

종종 화면을 스크롤하거나 텍스트 필드의 위치를 ​​조정하여 편집 할 때 쉽게 볼 수 있기 때문에 다루기가 까다로운 문제 일 수 있습니다. 다른 방법으로 텍스트 필드로 들어오고 나 가면서 많은 테스트를 수행해야합니다 (초기에는 항상 "완료"를 사용하여 다음 필드로 이동하는 대신 키보드를 닫을 수있는 옵션을 사용자에게 제공하십시오). 탐색 모음)


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

'완료'버튼을 눌렀을 때 키보드를 해제하는 가장 쉬운 방법은 다음과 같습니다.

헤더에 새로운 IBAction을 만듭니다.

- (IBAction)textFieldDoneEditing:(id)sender;

구현 파일 (.m 파일)에서 다음 메소드를 추가하십시오.

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

그런 다음 IBAction을 텍스트 필드에 연결하면 'Did End On Exit'이벤트에 연결하십시오.


하나의 간단한 개념을 이해하지 못하는 몇 가지 답변에 놀랐습니다. 앱의 컨트롤을 탐색하는 것은 뷰 자체가 해야하는 것이 아닙니다. 다음 응답자를 만들 제어를 결정하는 것은 컨트롤러 의 작업입니다.

또한 대부분의 답변은 앞으로 탐색에만 적용되지만 사용자는 뒤로 이동하기를 원할 수도 있습니다.

그래서 여기에 내가 생각해 낸 것이 있습니다. 양식은 뷰 컨트롤러에서 관리해야하며 뷰 컨트롤러는 응답자 체인의 일부입니다. 따라서 다음 방법을 완벽하게 구현할 수 있습니다.

#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들) 대신, 정직하자 컨트롤러 수준에서 논리를 관리 할 수 있습니다 적절한 장소 그렇게 할 .


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

이전 / 다음 버튼 기능을 구현하려는 경우 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

안녕하세요 모두들 이걸 봐주세요

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

나중에 검색 할 수있는 고유 한 태그 값으로 각 셀 (또는 UITextField) 을 할당하는 것을 기반으로보다 정교한 접근 방식을 사용 하여이 문제를 해결하려고했습니다 .activate-next-uitextfield-in-uitableview-iosUITableView

이게 도움이 되길 바란다!


이 물건 GNTextFieldsCollectionManager를 다룰 때 새로운 포드를 만들었습니다 . 다음 / 마지막 텍스트 필드 문제를 자동으로 처리하고 사용하기 매우 쉽습니다.

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

보기 계층 구조 (또는 태그)로 표시하여 정렬 된 모든 텍스트 필드를 가져 오거나 고유 한 textField 배열을 지정할 수 있습니다.


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
        }

    }

차라리 선호합니다 :

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

if (셀 == 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]; // ViewDidLoad에서 가변 배열 초기화
}

-(BOOL) textFieldShouldReturn : (UITextField *) textField
{

    int tag = (int) textField.tag;
    UITextField * txt = [self.array_Textfields objectAtIndex : tag];
    [txt는 FirstResponder가 됨];
    YES를 반환;
}

스토리 보드에 약 10+ 이상의 UITextField가 있었고 다음 기능을 활성화하는 방법은 UITextField 배열을 만들고 다음 UITextField를 firstResponder로 만드는 것입니다. 구현 파일은 다음과 같습니다.

#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

이것은 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.

이것은 태그를 사용하지 않고 스토리 보드 트릭을 사용하지 않고 신속하게 간단한 솔루션입니다 ...

이 확장명을 사용하십시오 :

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
    }

}

그리고 텍스트 필드 대리인과 함께 다음과 같이 호출하십시오.

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

누군가가 이것을 원한다면. 나는 이것이 요구되는 요구 사항에 가장 가깝다고 생각합니다.

여기에 이미지 설명을 입력하십시오

여기 내가 이것을 구현 한 방법이 있습니다.

다음을 사용하여 설정하려는 각 텍스트 필드에 대한 액세서리보기를 추가하십시오.

func setAccessoryViewFor(textField : UITextField)    {
    let toolBar = UIToolbar()
    toolBar.barStyle = .default
    toolBar.isTranslucent = true
    toolBar.sizeToFit()

    // Adds the buttons

    // Add previousButton
    let prevButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(previousPressed(sender:)))
    prevButton.tag = textField.tag
    if getPreviousResponderFor(tag: textField.tag) == nil {
        prevButton.isEnabled = false
    }

    // Add nextButton
    let nextButton = UIBarButtonItem(title: ">", style: .plain, target: self, action: #selector(nextPressed(sender:)))
    nextButton.tag = textField.tag
    if getNextResponderFor(tag: textField.tag) == nil {
        nextButton.title = "Done"
    }

    let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    toolBar.setItems([prevButton,spaceButton,nextButton], animated: false)
    toolBar.isUserInteractionEnabled = true
    textField.inputAccessoryView = toolBar
}

다음 기능을 사용하여 탭 처리

func nextPressed(sender : UIBarButtonItem) {
    if let nextResponder = getNextResponderFor(tag: sender.tag) {
        nextResponder.becomeFirstResponder()
    } else {
        self.view.endEditing(true)
    }

}

func previousPressed(sender : UIBarButtonItem) {
    if let previousResponder = getPreviousResponderFor(tag : sender.tag)  {
        previousResponder.becomeFirstResponder()
    }
}

func getNextResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag + 1) as? UITextField
}

func getPreviousResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag - 1) as? UITextField
}

다음 / 이전 버튼이 반응 할 순서대로 textFields 태그를 순서대로 제공해야합니다.


textFieldShouldReturn에서 현재 켜져있는 텍스트 필드가 다음을 클릭 할 때 마지막 텍스트 필드가 아니고 키보드를 닫지 않는지 확인해야합니다.


This is an old post, but has a high page rank so I'll chime in with my solution.

I had a similar issue and ended up creating a subclass of UIToolbar to manage the next/previous/done functionality in a dynamic tableView with sections: https://github.com/jday001/DataEntryToolbar

You set the toolbar as inputAccessoryView of your text fields and add them to its dictionary. This allows you to cycle through them forwards and backwards, even with dynamic content. There are delegate methods if you want to trigger your own functionality when textField navigation happens, but you don't have to deal with managing any tags or first responder status.

There are code snippets & an example app at the GitHub link to help with the implementation details. You will need your own data model to keep track of the values inside the fields.


Without usings tags and without adding a property for nextField/nextTextField, you can try this to emulate TAB, where "testInput" is your current active field:

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

I've been using Michael G. Emmons' answer for about a year now, works great. I did notice recently that calling resignFirstResponder and then becomeFirstResponder immediately can cause the keyboard to "glitch", disappearing and then appearing immediately. I changed his version slightly to skip the resignFirstResponder if the nextField is available.

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

}

you can use IQKeyboardManager library to do this. it handle every thing, you don't need any additional setup.IQKeyboardManager is available through CocoaPods, to install it simply add the following line to your Podfile:

pod 'IQKeyboardManager'

or Just drag and drop IQKeyBoardManager directory from demo project to your project. That's it. you can find IQKeyBoardManager directory from https://github.com/hackiftekhar/IQKeyboardManager

참고URL : https://stackoverflow.com/questions/1347779/how-to-navigate-through-textfields-next-done-buttons



반응형