iPhone 키보드의 "다음"버튼으로 모든 텍스트 필드를 탐색하려면 어떻게해야합니까?
마지막 텍스트 필드는 키보드를 닫아야합니다.
IB 버튼 (다음 / 완료)을 설정했지만 이제 막혔습니다.
textFieldShouldReturn 액션을 구현했지만 이제 다음 및 완료 버튼으로 키보드가 닫힙니다.
iPhone 키보드의 "다음"버튼으로 모든 텍스트 필드를 탐색하려면 어떻게해야합니까?
마지막 텍스트 필드는 키보드를 닫아야합니다.
IB 버튼 (다음 / 완료)을 설정했지만 이제 막혔습니다.
textFieldShouldReturn 액션을 구현했지만 이제 다음 및 완료 버튼으로 키보드가 닫힙니다.
답변:
Mac OS X 용 Cocoa에는 다음 응답자 체인이 있으며, 다음 응답기에 텍스트 필드에 어떤 제어에 초점을 두어야하는지 물어볼 수 있습니다. 이것이 텍스트 필드 사이의 탭을 작동시키는 것입니다. 그러나 iOS 기기에는 키보드가없고 터치 만 있기 때문에이 개념은 Cocoa Touch로 전환해도 살아남지 못했습니다.
어쨌든 다음 두 가지 가정을 통해 쉽게 수행 할 수 있습니다.
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.
}
더 많은 코드를 추가하면 가정도 무시할 수 있습니다.
스위프트 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!
UITableViewCell
입니다. 연결된 UITableView
텍스트 에 액세스하여 찾고있는 텍스트 필드가 포함 된 셀을 가져와야합니다.
UITextFieldDelegate
텍스트 필드 델리게이트 를 추가 하고 설정하는 것을 잊지 마십시오 .
가 많이 나는 그것을 처음봤을 때 저를 멀리 날려 더 우아한 해결책은. 혜택:
UITextField
과 UITextView
키보드 입력 UI 컨트롤 모두에서 작동하도록 확장 가능IBOutlet
nextField라는 속성 이있는 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
다음 응답자가 될 다음 객체에 할당 할 수 있다는 것입니다.
또한 텍스트 필드 루프와 같은 멋진 작업을 수행하여 마지막 필드가 포커스를 잃은 후 첫 번째 필드가 다시 포커스를받을 수 있습니다.
nextField가 할당 된 경우 수동으로 구성하는 것 중 하나를 수동으로 구성 하기 위해 returnKeyType
의 를 자동으로 할당하도록 쉽게 확장 할 수 있습니다 .SOTextField
UIReturnKeyNext
UITableView
있습니다. IBOutlet
각 텍스트 필드의 뷰 컨트롤러에 속성이 있지만 nextField
속성을 파일 소유자의 해당 속성에 연결할 수는 없습니다 . 이 시나리오에서 어떻게 작동시킬 수 있습니까?
textField1.nextField = textField2; textField2.nextField = textField3;
등
대표단이없는 사람은 다음과 같습니다.
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
).
[tfN addTarget:self action:@selector(loginButtonTapped:) forControlEvents:UIControlEventEditingDidEndOnExit];
. 감사합니다 @mxcl.
이 문제에 대한 해결책은 다음과 같습니다.
이 문제를 해결하기 위해 (그리고 태그를 사용하여 작업하는 것을 싫어하기 때문에) 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)
}
}
UITextFieldDelegate
하고 구현할 수 func textFieldDidEndEditing(textField: UITextField)
있습니다. 경우 일찍 반환하십시오 textField != field3
.
보다 일관되고 강력한 방법은 NextResponderTextField 를 사용
하는 것 view.tag
입니다. 델리게이트를 설정하거나 사용할 필요없이 인터페이스 빌더에서 완전히 구성 할 수 있습니다 .
당신이해야 할 일은
UITextField
할NextResponderTextField
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;
}
다음은 UIControl에서 카테고리를 사용하여 탭하는 구현입니다. 이 솔루션은 Michael과 Anth0의 메소드의 모든 장점을 가지고 있지만 UITextField
s 뿐만 아니라 모든 UIControl에 작동합니다 . 또한 Interface Builder 및 스토리 보드와 완벽하게 작동합니다.
소스 및 샘플 앱 : UIControlsWithTabbing 용 GitHub 저장소
용법:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField transferFirstResponderToNextControl];
return NO;
}
헤더:
//
// 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
키패드 반환 키를 표시 하는 위치는 어디 입니까?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
}
UITextView
. 어떻게 조합 하여이 작업을 수행 할 수 있습니까?
UITextField
(한 줄로 입력), 다른 하나는 UITextView
(여러 줄로 입력)입니다. UITextView
분명히이 코드에는 응답하지 않지만 형태로 사용될 수 있습니다.
한 텍스트 필드를 종료 한 후 [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'이벤트에 연결하십시오.
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;
}
하나의 간단한 개념을 이해하지 못하는 몇 가지 답변에 놀랐습니다. 앱의 컨트롤을 탐색하는 것은 뷰 자체가 해야하는 것이 아닙니다. 다음 응답자를 만들 제어를 결정하는 것은 컨트롤러 의 작업입니다.
또한 대부분의 답변은 앞으로 탐색에만 적용되지만 사용자는 뒤로 이동하기를 원할 수도 있습니다.
그래서 여기에 내가 생각해 낸 것이 있습니다. 양식은 뷰 컨트롤러에서 관리해야하며 뷰 컨트롤러는 응답자 체인의 일부입니다. 따라서 다음 방법을 완벽하게 구현할 수 있습니다.
#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
들) 대신, 정직하자 컨트롤러 수준에서 논리를 관리 할 수 있습니다 적절한 장소 그렇게 할 .
이전 / 다음 버튼 기능을 구현하려는 경우 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
}
}
누군가가 이걸 원한다면 나는 이것이 요구되는 요구 사항에 가장 가깝다고 생각합니다.
여기 내가 이것을 구현 한 방법이 있습니다.
다음을 사용하여 설정하려는 각 텍스트 필드에 대한 액세서리보기를 추가하십시오.
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 태그를 순서대로 제공해야합니다.
차라리 선호합니다 :
@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
}
다음을 가정하면 더 안전하고 직접적인 방법입니다.
스위프트 4.1 :
extension ViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let nextTag = textField.tag + 1
guard let nextTextField = textField.superview?.viewWithTag(nextTag) else {
textField.resignFirstResponder()
return false
}
nextTextField.becomeFirstResponder()
return false
}
}
이 게시물은 오래된 게시물이지만 페이지 순위가 높으므로 내 솔루션에 대해 설명하겠습니다.
비슷한 문제가 발생 UIToolbar
하여 섹션이있는 동적 tableView에서 다음 / 이전 / 완료 기능을 관리 하는 하위 클래스를 만들었습니다 . https://github.com/jday001/DataEntryToolbar
툴바를 텍스트 필드의 inputAccessoryView로 설정하고 사전에 추가합니다. 이를 통해 동적 컨텐츠에서도 앞뒤로 순환 할 수 있습니다. textField 탐색이 발생할 때 고유 한 기능을 트리거하려는 경우 대리자 메소드가 있지만 태그 또는 첫 번째 응답자 상태를 처리 할 필요는 없습니다.
GitHub 링크에는 코드 스 니펫 및 예제 앱이 있으며 구현 세부 정보를 도와줍니다. 필드 내부의 값을 추적하려면 자체 데이터 모델이 필요합니다.
태그를 사용하지 않고 nextField / nextTextField에 대한 속성을 추가하지 않으면 "testInput"이 현재 활성 필드 인 TAB를 에뮬레이트하기 위해이를 시도 할 수 있습니다.
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];
}];
나는 약 1 년 동안 Michael G. Emmons의 대답을 사용 해 왔으며 훌륭하게 작동합니다. 최근 resignFirstResponder를 호출 한 다음 FirstFirstsResponder가되면 즉시 키보드가 "고정"되어 사라졌다가 즉시 나타날 수 있습니다. nextField를 사용할 수 있으면 resignFirstResponder를 건너 뛰기 위해 그의 버전을 약간 변경했습니다.
-(BOOL) textFieldShouldReturn : (UITextField *) textField { if ([textField isKindOfClass : [NRTextField 클래스]]) { NRTextField * nText = (NRTextField *) textField; if ([nText nextField]! = nil) { dispatch_async (dispatch_get_main_queue (), ^ {[[nText nextField] willFirstResponder]; }); } 그밖에{ [textField resignFirstResponder]; } } 그밖에{ [textField resignFirstResponder]; } true를 반환; }