ios - 키보드 - uitextfield focus




텍스트 필드를 탐색하는 방법(다음/완료 버튼) (20)

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

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

나는 IB에 버튼 (다음 / 완료)을 설치했지만 지금은 붙어 있습니다.

textFieldShouldReturn 액션을 구현했지만 이제는 다음 및 완료 버튼이 키보드를 닫습니다.


'완료'버튼을 눌렀을 때 키보드를 닫을 수있는 아주 쉬운 방법은 다음과 같습니다.

머리글에 새 IBAction 만들기

- (IBAction)textFieldDoneEditing:(id)sender;

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

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

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


Anth0 및 Answerbot에서 이미 제안한 OO 솔루션이 마음에 듭니다. 그러나, 나는 빠르고 작은 POC로 작업하고 있었기 때문에 하위 클래스와 카테고리로 물건을 어지럽히고 싶지 않았습니다.

또 다른 간단한 해결책은 필드의 NSArray를 만들고 next를 누를 때 다음 필드를 조회하는 것입니다. 객체 지향 솔루션은 아니지만 빠르고 간단하며 구현하기 쉽습니다. 또한 한눈에 주문을보고 수정할 수 있습니다.

여기에 내 코드 (이 스레드에서 다른 답변을 바탕으로) :

@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를 반환합니다. 그냥 예를 반환했을 때 자동으로 후속 필드를 종료하거나 내 TextView에 줄 바꿈을 삽입 했으므로 그 점을 지적했을 것입니다. 그 점을 이해하는 데 약간 시간이 걸렸습니다.
  • 키보드에서 필드를 숨기기 위해 스크롤이 필요한 경우 activeField는 활성 필드를 추적합니다. 비슷한 코드를 사용하는 경우 첫 번째 응답자를 변경하기 전에 activeField를 할당해야합니다. 첫 번째 응답자를 변경하면 즉시 KeyboardWasShown 이벤트가 발생합니다.

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

이게 도움이 되길 바란다!


나는 많은 코드를 시험해 보았고 마침내 이것이 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 는 키패드가 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
 }

나는 오히려 다음을 선호합니다.

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

내 스토리 보드에 약 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

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

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를 결정할 수 있습니다 (하지만 위의 프로그래밍 솔루션만큼 우아하지는 않으므로 IMO는 위의 코드를 사용하여 viewDidLoad ).


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

방금이 GNTextFieldsCollectionManager 와 관련된 새로운 Pod를 만들었습니다. 그것은 자동으로 다음 / 마지막 textField 문제를 처리하고 매우 사용하기 쉽습니다 :

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

뷰 계층 구조 (또는 태그)로 나타나는 모든 텍스트 필드를 정렬하거나 사용자가 직접 지정한 textField 배열을 지정할 수 있습니다.


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

당신이해야 할 일은

  1. UITextField 의 클래스 유형을 NextResponderTextField
  2. 그런 다음 nextResponderField 의 콘센트를 다음 응답자를 가리 키도록 설정합니다. UITextField 또는 UIResponder 하위 클래스 일 수 있습니다. 또한 UIButton 일 수도 있고 라이브러리가 활성화되어있는 경우에만 버튼의 TouchUpInside 이벤트를 트리거 할 정도로 똑똑합니다.

다음은 실제 활동중인 도서관입니다.


이것은 나를 위해 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 내부 에는 다음이 포함됩니다.

TextField에 태그가 설정되어 있지 않으면 지금 설정하십시오.

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.

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

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

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

한 텍스트 필드를 끝내면 [otherTextField becomeFirstResponder]를 호출하고 다음 필드가 포커스를받습니다.

처리하는 까다로운 문제 일 수 있습니다. 종종 화면을 스크롤하거나 텍스트 필드의 위치를 ​​조정하여 편집 할 때 쉽게 볼 수 있기 때문입니다. 텍스트 필드 안팎을 여러 가지 방법으로 테스트하고 빠져 나오면서 많은 테스트를 수행해야합니다. (사용자에게 다음 필드로 이동하는 대신 항상 키보드를 닫을 수있는 옵션을 제공합니다. 일반적으로 "완료"와 함께 탐색 바)


textFieldShouldReturn에서 당신이 현재 클릭하고있는 텍스트 필드가 다음에 클릭 할 때 그리고 키보드를 닫지 않았는지 확인해야합니다.


using 태그를 사용하지 않고 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];
                                                    }];

이것은 태그없이, 스토리 보드 트릭없이, 신속한 간단한 솔루션입니다 ...

이 확장 프로그램을 사용하십시오.

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
}

IQKeyboardManager 라이브러리를 사용하여이를 수행 할 수 있습니다. 그것은 모든 것을 처리합니다. 추가 설정이 필요하지 않습니다 .IQKeyboardManager는 CocoaPods를 통해 사용할 수 있습니다. 설치하려면 Podfile에 다음 행을 추가하기 만하면됩니다.

pod 'IQKeyboardManager'

또는 IQKeyBoardManager 디렉토리를 데모 프로젝트에서 프로젝트로 드래그 앤 드롭하십시오. 그게 전부 야.https://github.com/hackiftekhar/IQKeyboardManager 에서 IQKeyBoardManager 디렉토리를 찾을 수 있습니다.https://github.com/hackiftekhar/IQKeyboardManager


여기 Anth0 의 대답 중 Swift 3 버전이 있습니다. 나는 신속한 개발자들이 그의 위대한 대답을 이용하기를 원할 때 그것을 돕기 위해 여기에 올리고있다. 나는 당신이 관련된 객체를 설정할 때 리턴 키 타입 인 "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.

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




iphone