IPhoneキーボードの[次へ]ボタンを使用して、すべてのテキストフィールドを移動する方法はありますか。
最後のテキストフィールドはキーボードを閉じるはずです。
私はIBのボタンを設定しました(Next/Done)が、今立ち往生しています。
TextFieldShouldReturnアクションを実装しましたが、[Next]ボタンと[Done]ボタンでキーボードを閉じます。
Mac OS X用のCocoaでは、次のレスポンダチェーンがあります。そこで、次にどのコントロールにフォーカスを置くべきかをテキストフィールドに尋ねることができます。これがテキストフィールド間のタブ移動を機能させるものです。しかし、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!
もっともっと洗練された解決策がありますが、それを初めて見たときには気がつかなかった。利点:
UITextField
コントロールとUITextView
コントロールの両方、または任意のキーボード入力UIコントロールと連携するように拡張することができます。NextFieldというIBOutlet
プロパティを持つUITextFieldサブクラスを作成します。これがヘッダです。
@interface SOTextField : UITextField
@property (weak, nonatomic) IBOutlet UITextField *nextField;
@end
そして、これが実装です。
@implementation SOTextField
@end
View Controllerで、-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
オブジェクトに割り当てることができるという点です。
さらに、textFieldをループするなど、クールなことを実行して、最後のフォーカスが失われた後、最初のフォーカスが再びフォーカスを受けるようにすることもできます。
NextFieldが割り当てられている場合は、これを簡単に拡張してreturnKeyType
のSOTextField
をUIReturnKeyNext
に自動的に割り当てることができます。手動で設定する必要が1つ少なくなります。
これは委任なしのものです。
tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
目的:
[tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
[tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
(ほとんど未知の)UIControlEventEditingDidEndOnExit
UITextField
アクションを使って動作します。
これをストーリーボードに簡単に接続することもできるので、またはの委任コードは必要ありません。
編集:実際に私はストーリーボードでこれを接続する方法を把握することはできません。 becomeFirstResponder
は、この制御イベントに対して提供されるアクションではないようです(残念です)。それでも、すべてのテキストフィールドをViewControllerの単一のアクションにフックして、送信者に基づいてどのtextFieldを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の答えを適用する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])
拡張機能は、最後のフィールドを除くすべてのフィールドでリターンボタンを「次へ」に設定し、最後のフィールドを「完了」に設定し、これらをタップするとフォーカスを移動/キーボードを閉じます。
Swift <2.3
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for var i = 0; i < fields.count - 1; i += 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
}
Swift 3:こんな使い方 -
UITextField.connectFields(fields: [field1, field2])
Extension:
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .next
fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
}
last.returnKeyType = .go
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
}
}
より一貫性のある堅牢な方法は、 NextResponderTextField を使用することです。デリゲートを設定したりview.tag
を使用したりすることなく、インターフェースビルダーから完全に設定できます。
あなたがする必要があるのはただ
UITextField
のクラス型をNextResponderTextField
に設定します。 nextResponderField
のアウトレットを設定します。それは、UITextField
または任意のUIResponder
サブクラスにすることができます。これはUIButtonでも構いませんし、ライブラリはボタンのTouchUpInside
イベントが有効になっている場合にのみトリガするのに十分スマートです。 これが実行中のライブラリです。
私はすでにAnth0とAnswerbotによって提案されているOO解決策が好きです。しかし、私はすばやく小さなPOCに取り組んでいたので、サブクラスやカテゴリを使って物事を整理したくはありませんでした。
もう1つの簡単な解決策は、フィールドの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
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
}
1つのテキストフィールドを終了したら、[otherTextField becomeFirstResponder]を呼び出すと、次のフィールドにフォーカスが移ります。
画面をスクロールしたり、テキストフィールドの位置を調整したりして編集時に見やすくすることもよくあるので、これは実際には扱いにくい問題になる可能性があります。さまざまな方法でテキストフィールドに出入りし、また早めに(多くの場合は "Done"で次のフィールドに移動するのではなく、キーボードを閉じるオプションを常に与えるようにして)たくさんのテストを行うようにしてください。ナビゲーションバー)
-(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をtextfieldにリンクするとき - 'Did End On Exit'イベントにリンクします。
ここでの答えがいくつかの単純な概念を理解するのに失敗することに驚いています。あなたのアプリのコントロールをナビゲートすることは、ビュー自体がするべきことではありません。次の最初のレスポンダにするコントロールを決めるのはコントローラの仕事です。
また、ほとんどの回答は前方へのナビゲートにしか適用されませんでしたが、ユーザーは後方への移動も望んでいる可能性があります。
だからここに私が思い付いたものです。フォームはView Controllerによって管理する必要があり、View Controllerはレスポンダチェーンの一部です。だから、あなたは完全に次のメソッドを実装するのは自由です:
#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];
}
事前に表示されているオフスクリーンレスポンダをスクロールするための追加のロジックが適用される場合があります。
このアプローチのもう1つの利点は、(UITextField
sのように)表示したいすべての種類のコントロールをサブクラス化する必要がなく、代わりにコントローラレベルでロジックを管理できることです。ここで、正直なところ、です。 )正しい場所.
最初に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;
}
このものを扱うときに私はちょうど新しいPodを作成しました GNTextFieldsCollectionManager 。それは自動的に次の/最後のtextField問題を処理し、そしてとても使いやすいです:
[[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
}
}
みなさん、こんにちは。 こちらをご覧ください
- (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
これが役に立つことを願っています!
前/次ボタン機能を実装しようと思っている場合に備えて、私は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
これは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がTagを持っていないなら今それを設定します:
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.
これはSwiftのシンプルなソリューションです。タグを使用せず、ストーリーボードのトリックも不要です。
この拡張子を使うだけです:
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
}
私はむしろ好きです:
@interface MyViewController : UIViewController
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
@end
NIBファイルで、私はこのinputFields配列に望みの順序でtextFieldsをフックします。その後、ユーザーがreturnをタップしたことを報告する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(cell == nil) cell [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; txt_Input = [[UITextField alloc] initWithFrame:CGRectMake(0) 、10,150,30)]; [...] txt_Input.tag = indexPath.row + 1; [......] [self.array_Textfield addObject:txt_Input]; [10。 // ViewDidLoadの可変配列を初期化する } - (BOOL)textFieldShouldReturn:(UITextField *)textField { int tag =(int)textField.tag; UITextField * txt = [self.array_Textfields objectAtIndex:tag]; [txt becomeFirstResponder]; 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
誰かがこのように欲しいなら。私はこれが問題に求められている要件に最も近いと思います
これは私がこれをどのように実装したかです。
を使用して、設定したい各テキストフィールドにアクセサリビューを追加します。
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タグを、next/prevボタンを反応させたい順番に並べる必要があります。
タグを使わずに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];
}];
textFieldShouldReturnでは、現在クリックしているテキストフィールドが、次にクリックするときに最後のものではないこと、およびキーボードを消さないことを確認してください。
私は約1年間Michael G. Emmonsの答えを使ってきました。私は最近resignFirstResponderを呼び出してからすぐにfirstFirstResponderを呼び出すとキーボードが「グリッチ」し、消えてすぐに表示される可能性があることに最近気付きました。 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] becomeFirstResponder];}); } else { [textField resignFirstResponder]; } } else { [textField resignFirstResponder]; } trueを返します; }
これはAnth0の答えのSwift 3バージョンです。私はここに投稿して、Swiftの開発者が彼のすばらしい答えを利用したいと思っているのを助けます。関連付けられたオブジェクトを設定するときに、戻りキーの種類として "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.
これは古い投稿ですが、ページランクが高いため、このソリューションを使用します。
私は同様の問題を抱えていて、セクションを持つ動的tableViewでnext/previous/done機能を管理するためにUIToolbar
のサブクラスを作成することになりました: https://github.com/jday001/DataEntryToolbar
あなたはあなたのテキストフィールドのinputAccessoryViewとしてツールバーを設定し、それらをその辞書に追加します。これにより、動的コンテンツの場合でも、前後に順番に切り替えることができます。 textFieldナビゲーションが発生したときに独自の機能を起動したい場合はデリゲートメソッドがありますが、タグやファーストレスポンダのステータスを管理する必要はありません。
GitHubのリンクに実装の詳細を説明するコードスニペットとサンプルアプリケーションがあります。フィールド内の値を追跡するには、独自のデータモデルが必要になります。
これを行うにはIQKeyboardManagerライブラリを使用できます。それはあらゆることを処理します、あなたは追加の設定を必要としません。それをインストールするためにCocoaPodsを通して利用可能です。
pod 'IQKeyboardManager'
またはデモプロジェクトからIQKeyBoardManagerディレクトリをプロジェクトにドラッグアンドドロップするだけです。それでおしまい。あなたは からIQKeyBoardManagerディレクトリを見つけることができますhttps://github.com/hackiftekhar/IQKeyboardManager
より安全で直接的な方法です。
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
}
}
Swift 3 Solution、UITextField's
の順序配列を使用
func nextTextField() {
let textFields = // Your textfields array
for i in 0 ..< textFields.count{
if let textfield = textFields[i], textfield.isFirstResponder{
textfield.resignFirstResponder()
if i+1 < textFields.count, let nextextfield = textFields[i+1]{
nextextfield.becomeFirstResponder()
return
}
}
}
}