我使用“返回键”的“下一个”值来获取“下一步”按钮代替“完成”按钮,但是(显然)按下它不会自动移动到我视图中的下一个UITextField。
这样做的正确方法是什么?我见过很多答案,但是任何人都有快速的解决方案吗?
答案 0 :(得分:82)
确保您的文本字段设置了委托并实施textFieldShouldReturn
方法。这是当用户点击返回键时调用的方法(无论它看起来如何)。
该方法可能如下所示:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == self.field1 {
self.field2.becomeFirstResponder()
}
return true
}
这里的实际逻辑可能会有所不同。有很多方法,如果你有很多文本字段,我肯定会建议大量的if
/ else
链,但这里的要点是确定当前有效的视图确定哪个视图应该变为活动状态。在您确定哪个视图应处于有效状态后,请调用该视图的becomeFirstResponder
方法。
对于某些代码清洁度,您可以考虑使用UITextField
扩展名,如下所示:
private var kAssociationKeyNextField: UInt8 = 0
extension UITextField {
var nextField: UITextField? {
get {
return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
}
set(newField) {
objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
}
}
}
然后将我们的textFieldShouldReturn
方法更改为:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.nextField?.becomeFirstResponder()
return true
}
完成此操作后,只需在nextField
中设置每个文本字段的新viewDidLoad
属性即可:
self.field1.nextField = self.field2
self.field2.nextField = self.field3
self.field3.nextField = self.field4
self.field4.nextField = self.field1
虽然如果我们真的想要,我们可以在属性前加@IBOutlet
,这样我们就可以连接我们的" nextField"界面构建器中的属性。
将扩展名更改为如下所示:
private var kAssociationKeyNextField: UInt8 = 0
extension UITextField {
@IBOutlet var nextField: UITextField? {
get {
return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
}
set(newField) {
objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
}
}
}
现在在界面构建器中连接nextField
属性:
(在你这里也设置你的代表。)
当然,如果nextField
属性返回nil
,键盘就会隐藏。
答案 1 :(得分:8)
以下是Swift的一个例子:
我创建了一个包含6 UITextField
秒的屏幕。我在Interface Builder中为它们分配了标签1到6。我还在IB中将Return键更改为Next。然后我实现了以下内容:
import UIKit
// Make your ViewController a UITextFieldDelegate
class ViewController: UIViewController, UITextFieldDelegate {
// Use a dictionary to define text field order 1 goes to 2, 2 goes to 3, etc.
let nextField = [1:2, 2:3, 3:4, 4:5, 5:6, 6:1]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Make ourselves the delegate of the text fields so that textFieldShouldReturn
// will be called when the user hits the Next/Return key
for i in 1...6 {
if let textField = self.view.viewWithTag(i) as? UITextField {
textField.delegate = self
}
}
}
// This is called when the user hits the Next/Return key
func textFieldShouldReturn(textField: UITextField) -> Bool {
// Consult our dictionary to find the next field
if let nextTag = nextField[textField.tag] {
if let nextResponder = textField.superview?.viewWithTag(nextTag) {
// Have the next field become the first responder
nextResponder.becomeFirstResponder()
}
}
// Return false here to avoid Next/Return key doing anything
return false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
答案 2 :(得分:2)
其他答案没有任何问题,这只是一种不同的方法,有利于更专注于OOP - imho(尽管前面有点工作,但可以重复使用)。在故事板中,我开始添加具有不同范围(例如800-810)的标签,这些标签定义了我想要在其间移动的字段的特定顺序。这样做的好处是可以在主视图中处理所有子视图,以便可以根据需要在UITextField和UITextView(以及任何其他控件)之间进行导航。
通常 - 我通常尝试在视图和自定义事件处理程序对象之间使用视图控制器消息。所以我使用从自定义委托类传递回视图控制器的消息(aka,NSNotification)。
(TextField Delegate Handler)
注意:在AppDelegate.swift中:let defaultCenter = NSNotificationCenter.defaultCenter()
//Globally scoped
struct MNGTextFieldEvents {
static let NextButtonTappedForTextField = "MNGTextFieldHandler.NextButtonTappedForTextField"
}
class MNGTextFieldHandler: NSObject, UITextFieldDelegate {
var fields:[UITextField]? = []
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.backgroundColor = UIColor.yellowColor()
}
func textFieldDidEndEditing(textField: UITextField) {
textField.backgroundColor = UIColor.whiteColor()
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
return true
}
func textFieldShouldClear(textField: UITextField) -> Bool {
return false
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
//passes the message and the textField (with tag) calling the method
defaultCenter.postNotification(NSNotification(name: MNGTextFieldEvents.NextButtonTappedForTextField, object: textField))
return false
}
}
这使我的视图控制器能够专注于处理对象,模型和视图之间的消息传递的主要工作。
(View Controller从代理接收消息并使用advanceToNextField函数传递指令)
注意:在我的故事板中,我的自定义处理程序类是使用NSObject定义的,并且该对象作为我需要监视的控件的委托链接到故事板中。这导致自动初始化自定义处理程序类。
class MyViewController: UIViewController {
@IBOutlet weak var tagsField: UITextField! { didSet {
(tagsField.delegate as? MNGTextFieldHandler)!.fields?.append(tagsField)
}
}
@IBOutlet weak var titleField: UITextField!{ didSet {
(titleField.delegate as? MNGTextFieldHandler)!.fields?.append(titleField)
}
}
@IBOutlet weak var textView: UITextView! { didSet {
(textView.delegate as? MNGTextViewHandler)!.fields?.append(textView)
}
}
private struct Constants {
static let SelectorAdvanceToNextField = Selector("advanceToNextField:")
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
registerEventObservers()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
deRegisterEventObservers()
}
func advanceToNextField(notification:NSNotification) {
let currentTag = (notification.object as! UIView).tag
for aView in self.view.subviews {
if aView.tag == currentTag + 1 {
aView.becomeFirstResponder()
}
}
}
func registerEventObservers () {
defaultCenter.addObserver(self, selector: Constants.SelectorAdvanceToNextField, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
}
func deRegisterEventObservers() {
defaultCenter.removeObserver(self, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
}
....
}
答案 3 :(得分:1)
实现我发现有用的结果的另一种方法。我的应用有11个文本字段,后跟文本视图。我需要能够使用下一个键循环遍历所有字段,然后在textview之后重新设置键盘(即其他注释)。
在故事板中,我在所有字段(文本和文本视图)上设置标记,从1到12开始,12是文本视图。
我确定还有其他方法可以做到,这种方法并不完美,但希望它可以帮到某人。
在代码中,我写了以下内容:
nslookup -query=txt _dmarc.mydomain.com
答案 4 :(得分:0)