iPhoneキーボードの[次へ]ボタンを使用してすべてのテキストフィールドをナビゲートするにはどうすればよいですか?
最後のテキストフィールドでキーボードを閉じる必要があります。
私はIB the Buttons(Next / Done)をセットアップしましたが、今は行き詰まっています。
textFieldShouldReturnアクションを実装しましたが、[次へ]ボタンと[完了]ボタンはキーボードを閉じます。
iPhoneキーボードの[次へ]ボタンを使用してすべてのテキストフィールドをナビゲートするにはどうすればよいですか?
最後のテキストフィールドでキーボードを閉じる必要があります。
私はIB the Buttons(Next / Done)をセットアップしましたが、今は行き詰まっています。
textFieldShouldReturnアクションを実装しましたが、[次へ]ボタンと[完了]ボタンはキーボードを閉じます。
回答:
Cocoa for Mac OS Xでは、次のレスポンダーチェーンがあり、どのコントロールに次にフォーカスするかをテキストフィールドに尋ねることができます。これにより、テキストフィールド間のタブ移動が機能します。しかし、iOSデバイスにはキーボードがなく、タッチしかないため、このコンセプトはCocoa Touchへの移行を乗り越えていません。
これはとにかく簡単に行うことができますが、2つの仮定があります。
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 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
クラスを使用するようにUITextFieldsを変更します。次に、IBでも、各 'SOTextFields'のデリゲートを 'File's Owner'に設定します(これは、デリゲートメソッドのコードを配置する場所-textFieldShouldReturn)。このデザインのすばらしいところは、任意のtextFieldを右クリックしてSOTextField
、次のレスポンダーにしたい次のオブジェクトにnextFieldアウトレットを割り当てることができることです。
さらに、textFieldsのループなどのクールなことを実行して、最後のフォーカスがフォーカスを失った後、最初のフォーカスが再びフォーカスを受け取るようにすることができます。
これは、簡単に自動的に割り当てるように拡張することができるreturnKeyType
のをSOTextField
にUIReturnKeyNext
1以下の事を手動での設定し- nextField割り当てがある場合。
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
、送信者に基づいてどのtextFieldを決定することができます(ただし、上記のプログラムによるソリューションほどエレガントではないため、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の回答を適用するSwift拡張(TravelerによりSwift 2.3に適応):
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
}
}
使い方は簡単です:
UITextField.connectFields([field1, field2, field3])
拡張機能は、最後のフィールドを除くすべてのフィールドで[戻る]ボタンを[次へ]に設定し、最後のフィールドを[完了]に設定します。これらをタップすると、フォーカスが移動/キーボードが非表示になります。
スウィフト<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)
}
}
UITextFieldDelegate
、実装させるだけfunc textFieldDidEndEditing(textField: UITextField)
です。もしそうなら、早く帰ってくださいtextField != field3
。
NextResponderTextFieldを使用するのがより一貫性があり堅牢な方法ですview.tag
。
デリゲートを設定したり、を使用したりすることなく、インターフェイスビルダーから完全に構成できます。
あなたがする必要があるのは
UITextField
しますNextResponderTextField
nextResponderField
、次のレスポンダを指すようにのアウトレットを設定します。これは、何でもUITextField
、どのUIResponder
サブクラスでもかまいません。UIButtonにすることもできます。ライブラリはTouchUpInside
、ボタンが有効になっている場合にのみボタンのイベントをトリガーするのに十分スマートです。
動作中のライブラリは次のとおりです。
私は、Anth0とAnswerbotによってすでに提案されているOOソリューションが好きです。ただし、私は迅速で小さなPOCに取り組んでいたため、サブクラスやカテゴリで乱雑にしたくありませんでした。
別の簡単な解決策は、フィールドのNSArrayを作成し、[次へ]を押したときに次のフィールドを検索することです。OOソリューションではありませんが、すばやく簡単に実装できます。また、順序を一目で確認および変更できます。
これが私のコードです(このスレッドの他の答えに基づいて構築されています):
@property (nonatomic) NSArray *fieldArray;
- (void)viewDidLoad {
[super viewDidLoad];
fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
}
- (BOOL) textFieldShouldReturn:(UITextField *) textField {
BOOL didResign = [textField resignFirstResponder];
if (!didResign) return NO;
NSUInteger index = [self.fieldArray indexOfObject:textField];
if (index == NSNotFound || index + 1 == fieldArray.count) return NO;
id nextField = [fieldArray objectAtIndex:index + 1];
activeField = nextField;
[nextField becomeFirstResponder];
return NO;
}
UIControlのカテゴリを使用したタブの実装は次のとおりです。このソリューションには、MichaelとAnth0のメソッドのすべての利点がありますが、すべてのUIControlsだけでなく、UITextField
s。また、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 [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
whereはキーパッドのリターンキーを表示し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
}
UITextView
。これを組み合わせて行う方法はありますか?
UITextField
(1行のテキストを入力)、もう1つはUITextView
(複数行のテキストを入力)です。UITextView
明らかにこのコードには応答しませんが、フォームで使用できます。
1つのテキストフィールドを終了した後、[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;
}
ここで回答の1つが1つの単純な概念を理解できていないことに驚いています。それはコントローラーです次の最初のレスポンダーを作成するためのコントロールを決定するの仕事です。
また、ほとんどの回答は前方にナビゲートする場合にのみ適用されますが、ユーザーは後方に移動することもできます。
これが私が思いついたものです。フォームはビューコントローラーで管理する必要があり、ビューコントローラーはレスポンダーチェーンの一部です。したがって、次のメソッドを完全に自由に実装できます。
#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
)を割り当てることに基づく、より洗練されたアプローチを使用してこの問題を解決しようとしましたUITableView
:
activate-next-uitextfield-in-uitableview-ios
これが役に立てば幸いです!
このGNTextFieldsCollectionManagerを処理するときに、新しいポッドを作成しました。次/最後のtextField問題を自動的に処理し、非常に使いやすいです。
[[GNTextFieldsCollectionManager alloc] initWithView:self.view];
ビュー階層に表示される(またはタグによって)ソートされたすべてのテキストフィールドを取得します。または、textFieldsの独自の配列を指定できます。
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
}
next / prevボタンを応答させたい順序で、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内には次のものがあります。
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.
これは、タグを使用せず、ストーリーボードのトリックを使用しない、迅速なシンプルなソリューションです...
この拡張機能を使用してください:
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
}
より安全で直接的な方法:
Swift 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のプロパティを追加せずに、これを試して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];
}];
マイケルG.エモンズの回答を1年ほど使用していますが、うまくいきます。最近、resignFirstResponderを呼び出してすぐにfirstFirstResponderを呼び出すと、キーボードが「グリッチ」し、消えてすぐに表示されることに気付きました。nextFieldが利用可能な場合、resignFirstResponderをスキップするように彼のバージョンを少し変更しました。
-(BOOL)textFieldShouldReturn:(UITextField *)textField { if([textField isKindOfClass:[NRTextField class]]) { NRTextField * nText =(NRTextField *)textField; if([nText nextField]!= nil){ dispatch_async(dispatch_get_main_queue()、 ^ {[[nText nextField] preventFirstResponder]; }); } そうしないと{ [textField resignFirstResponder]; } } そうしないと{ [textField resignFirstResponder]; } trueを返します。 }