问题
I have searched and seen a lot of answers about textFieldShouldReturn method. Half of them are outdated, some work in different cases, some are not explained thoroughly. I am not sure what is the most optimal way to do this task, it works but I think there might be an easier way to do it.
Heres my code so far:
On the header file:
@interface ClassName : SomeUIViewController <UITextFieldDelegate>
In the implementation file:
@interface ClassName()
@property (weak, nonatomic) IBOutlet UITextField *firstOne;
@property (weak, nonatomic) IBOutlet UITextField *secondOne;
@property (weak, nonatomic) IBOutlet UITextField *thirdOne;
@property (weak, nonatomic) IBOutlet UITextField *fourthOne;
@property (weak, nonatomic) IBOutlet UITextField *fifthOne;
@end
-(void)viewDidLoad{
self.firstOne.delegate = self;
self.secondOne.delegate = self;
self.thirdOne.delegate = self;
self.fourthOne.delegate = self;
self.fifthOne.delegate = self;
}
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
if (textField == self.firstOne) {
[textField resignFirstResponder];
[self.secondOne becomeFirstResponder];
} else if (textField == self.secondOne) {
[textField resignFirstResponder];
[self.thirdOne becomeFirstResponder];
} else if (textField == self.thirdOne) {
[textField resignFirstResponder];
[self.fourthOne becomeFirstResponder];
} else if (textField == self.fourthOne) {
[textField resignFirstResponder];
[self.fifthOne becomeFirstResponder];
} else if (textField == self.fifthOne) {
[textField resignFirstResponder];
}
return NO;
}
So is this correct or are there better ways to do this task?
回答1:
In general your code is fine.
If you are using IB (Interface Builder) you can set the delegate there instead of in code.
Example: control drag from the UITextField to the ViewController and select "delegate".
The resignFirstResponder could be factored to ibe occurrence
Refactored code:
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
[textField resignFirstResponder];
if (textField == self.firstOne) {
[self.secondOne becomeFirstResponder];
} else if (textField == self.secondOne) {
[self.thirdOne becomeFirstResponder];
} else if (textField == self.thirdOne) {
[self.fourthOne becomeFirstResponder];
} else if (textField == self.fourthOne) {
[self.fifthOne becomeFirstResponder];
}
return NO;
}
回答2:
I propose you an other way to do this. You can create a new class, extending UITextField class with a category, and add your own property to navigate between UIControls.
// Class name UITextField+Navigation.h
@interface UITextField (Navigation)
@property (weak, nonatomic) IBOutlet id nextUIControl;
@end
The IBOutlet is for if you want to use the property with the storyboard, you can omit it if you want.
// UITextField+Navigation.m
#import "UITextField+Navigation.h"
#import <objc/runtime.h>
static char defaultHashKey;
@implementation UITextField (Navigation)
- (id)nextUIControl
{
return objc_getAssociatedObject(self, &defaultHashKey);
}
- (void)setNextUIControl:(id)nextUIControl
{
objc_setAssociatedObject(self, &defaultHashKey, nextUIControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
In your class, import the extended UITextField+Navigation.h class so you can access the property you have created. In the viewDidLoad method you just assign the value of the next UITextField
#import "UITextField+Navigation.h"
@interface ClassName()
@property (weak, nonatomic) IBOutlet UITextField *firstOne;
@property (weak, nonatomic) IBOutlet UITextField *secondOne;
@property (weak, nonatomic) IBOutlet UITextField *thirdOne;
@property (weak, nonatomic) IBOutlet UITextField *fourthOne;
@property (weak, nonatomic) IBOutlet UITextField *fifthOne;
@end
- (void)viewDidLoad
{
self.firstOne.nextUIControl = self.secondOne;
self.secondOne.nextUIControl = self.thirdOne;
etc...
}
Or if you are using Storyboards, you can link the controllers to the nextUIControl property.
And in the textFieldShouldReturn:
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
[textField.nextUIControl becomeFirstResponder];
return NO;
}
回答3:
My 50 cents. I use the next approach. UIKit objects (UIView, UITextField and other) have a rewritable property called "tag". It's a property for developer use.
typedef NS_ENUM (NSInteger, SSSActionType) {
TextFieldTag1= 100,
TextFieldTag2= 110,
TextFieldTag3= 120
};
- (void)customizeFields {
textField1.tag = TextFieldTag1;
textField1.delegate = self;
// setting tags for all fields
}
In delegate methods compare integer tags instead of instance objects:
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
[textField resignFirstResponder];
switch (textField.tag) {
case TextFieldTag1:
// do stuff
break;
case TextFieldTag2:
break;
case TextFieldTag3:
break;
default:
break;
}
return NO;
}
Looks like the first approach but I prefer explicit tags name and clear code
回答4:
as well as above good answers . you can still findout good library who manage all the stuffs of textfield . like when you are using textfields in tableview , textfields in collectionview . https://github.com/michaeltyson/TPKeyboardAvoiding. by using this library you can easily make login or sign up forms for app
回答5:
My solution in Swift:
Create a dictionary mapping between a TextField and the next one.
// to find the next text field
private lazy var textFields: [UITextField: UITextField] =
[self.firstTF: self.secondTF,
self.secondTF: self.thirdTF]
func textFieldShouldReturn(textField: UITextField) -> Bool {
textFields[textField]?.becomeFirstResponder()
return true
}
回答6:
I put every textfield a tag number consecutive. like 0,1,2,3..n then the usage is:
func textFieldShouldReturn(textField: UITextField) -> Bool {
let tag = textField.tag
if (tag < n)
{
let textfieldNew = theView.viewWithTag(tag + 1) as! UITextField
textfieldNew.becomeFirstResponder()
}
else
{
textField.resignFirstResponder()
}
return true
}
来源:https://stackoverflow.com/questions/21687778/text-field-should-return-is-this-correct-for-ios7