我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
我如何通过iPhone键盘上的“下一步”按钮浏览所有的文本字段?
最后一个文本字段应该关闭键盘。
我已经设置了IB按钮(下一步/完成),但现在我卡住了。
我实现了textFieldShouldReturn动作,但现在下一步和完成按钮关闭键盘。
当前回答
这是一个老帖子,但有一个很高的页面排名,所以我将附和我的解决方案。
我有一个类似的问题,最终创建了UIToolbar的子类来管理动态tableView中的下一个/前一个/完成功能:https://github.com/jday001/DataEntryToolbar
您将工具栏设置为文本字段的inputAccessoryView,并将它们添加到它的字典中。这允许您向前和向后循环浏览它们,即使是动态内容。有委托方法,如果你想触发你自己的功能时textField导航发生,但你不必处理管理任何标签或第一个响应器状态。
在GitHub链接中有代码片段和示例应用程序,以帮助实现细节。您需要自己的数据模型来跟踪字段中的值。
其他回答
退出一个文本字段后,调用[otherTextField becomeFirstResponder],下一个字段获得焦点。
这实际上是一个棘手的问题,因为通常你还想滚动屏幕或以其他方式调整文本字段的位置,以便在编辑时容易看到。只要确保做大量的测试,以不同的方式进入和退出文本字段,并提前离开(总是给用户一个选项,取消键盘,而不是进入下一个字段,通常在导航栏中有“完成”)
在Mac OS X的Cocoa中,你有下一个响应器链,在那里你可以询问文本字段下一个控件应该有焦点。这就是在文本字段之间进行标签操作的原因。但由于iOS设备没有键盘,只有触摸,所以这一概念没有在Cocoa touch的过渡中幸存下来。
这很容易做到,只要有两个假设:
所有“tabbable”UITextFields都在同一个父视图上。 它们的“制表符顺序”由tag属性定义。
假设你可以重写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
}
如果文本字段的superview是一个UITableViewCell那么下一个responder将是
let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
一个快速扩展,应用mxcl的答案,使这特别容易(适应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)
}
}
斯威夫特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)
}
}
有一个更优雅的解决方案,让我第一次看到它的时候就大吃一惊。好处:
更接近OSX文本框的实现,其中一个文本框知道下一步的重点应该去哪里 不依赖于设置或使用标签-这是,IMO脆弱的用例 可以扩展工作与UITextField和UITextView控件-或任何键盘输入UI控件 不会让你的视图控制器与样板UITextField委托代码混淆 很好地与IB集成,并可以通过熟悉的选项-拖放连接插座进行配置。
创建一个UITextField子类,它有一个名为nextField的IBOutlet属性。下面是标题:
@interface SOTextField : UITextField
@property (weak, nonatomic) IBOutlet UITextField *nextField;
@end
这是它的实现:
@implementation SOTextField
@end
在你的视图控制器中,你将创建-textFieldShouldReturn: delegate方法:
- (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,改变你的UITextFields使用SOTextField类。接下来,同样在IB中,设置每个“SOTextFields”的委托为“文件的所有者”(这是你把委托方法的代码- textFieldShouldReturn)。这种设计的美妙之处在于,现在你可以简单地右键单击任何textField,并将nextField出口分配给你想成为下一个响应器的下一个SOTextField对象。
此外,您还可以做一些很酷的事情,如循环textFields,以便在最后一个失去焦点后,第一个将再次获得焦点。
这可以很容易地扩展到自动分配SOTextField的returnKeyType到一个UIReturnKeyNext,如果有一个nextField分配-少一个手动配置的东西。
下面是一个在UIControl上使用类别的选项卡实现。这个解决方案具有Michael和Anth0方法的所有优点,但适用于所有uicontrol,而不仅仅是UITextFields。它还可以与接口生成器和故事板无缝工作。
源代码和示例应用程序: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