在 Swift 中点击返回键时如何关闭 UIAlertController?

Posted

技术标签:

【中文标题】在 Swift 中点击返回键时如何关闭 UIAlertController?【英文标题】:How do I dismiss a UIAlertController when the return key is tapped in Swift? 【发布时间】:2018-04-19 15:51:23 【问题描述】:

我有一个带有两个按钮和一个文本字段的 UIAlertController。当点击保存按钮时,将执行转场。我还在textFieldShouldReturn 中设置了返回键来执行此操作。但是,当点击返回键时,警报控制器不会关闭。它向上移动到视图的左上角,并在返回视图时导致动画挂起。我还尝试使用myAlertController.dismiss(animated: false, completion: nil) 关闭警报控制器,但这会引发“尝试在视图不在窗口层次结构中的 UIAlertController 上呈现 UINavigationController”错误。当点击返回键并仍然执行 segue 时,如何关闭警报控制器?谢谢。

import UIKit
import CoreData

var albumNameFromTextfield: String = ""

class AlbumViewController: UIViewController, UITextFieldDelegate 

// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
@IBOutlet weak var noAlbumsView: UIView!

var albums: [NSManagedObject] = []

let newAlbumAlert = UIAlertController(title: "Create New Album", message: "Enter a name for your new album.", preferredStyle: UIAlertControllerStyle.alert)

// MARK: - Actions

@IBAction func unwindToAlbumsScreen(sender: UIStoryboardSegue) 


@IBAction func newAlbumTapped(_ sender: UIBarButtonItem) 
    createNewAlbum()


func createNewAlbum() 
    let nAA = newAlbumAlert
    present(nAA, animated: true, completion: nil)


// Alert controller setup
func createNewAlbumAlert() 
    let saveAction = UIAlertAction(title: "Save", style: .default, handler:  (action) in
        guard let textField = self.newAlbumAlert.textFields?[0],
            let nameToSave = textField.text else 
                return
        
        print("Album name has been inputted; save button tapped.")
        self.save(name: nameToSave)
        self.albumCollectionView.reloadData()
        self.performSegue(withIdentifier: "showNewAlbumViewController", sender: self)
    )

    newAlbumAlert.addTextField (textField: UITextField) in
        textField.placeholder = "Album Name"
        textField.keyboardType = .default
        textField.autocorrectionType = .default
        textField.returnKeyType = .done
        textField.delegate = self
        textField.enablesReturnKeyAutomatically = true
    

    newAlbumAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    newAlbumAlert.addAction(saveAction)



//Text field functions
func textFieldDidBeginEditing(_ textField: UITextField) 
    self.newAlbumAlert.actions[1].isEnabled = false
    textField.text = ""


func textFieldDidEndEditing(_ textField: UITextField) 
    albumNameFromTextfield = textField.text!
    print("Album name for nav title set.")


func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    let TFNameToSave = textField.text
    self.save(name: TFNameToSave!)
    self.albumCollectionView.reloadData()
    textField.resignFirstResponder()
    self.performSegue(withIdentifier: "segueForTF", sender: self)
    print("Album name has been inputted; return button tapped.")
    return true


@objc func editingChanged(_ textField: UITextField) 
    if textField.text?.count == 1 
        if textField.text?.first == " " 
            textField.text = ""
            return
        
    
    guard
        let alertControllerText = newAlbumAlert.textFields![0].text, !alertControllerText.isEmpty
    else 
        newAlbumAlert.actions[1].isEnabled = false
        return
    
    newAlbumAlert.actions[1].isEnabled = true


// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)

    //Core Date functions
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else 
            return
    
    let managedContext =
        appDelegate.persistentContainer.viewContext
    let fetchRequest =
        NSFetchRequest<NSManagedObject>(entityName: "Album")
    do 
        albums = try managedContext.fetch(fetchRequest)
     catch let error as NSError 
        print("Could not fetch. \(error), \(error.userInfo)")
    

    //Setup to do when the view will appear
    self.albumCollectionView.reloadData()

    if albums.count == 0 
        noAlbumsView.alpha = 1
     else 
        noAlbumsView.alpha = 0
    


override func viewDidLoad() 
    super.viewDidLoad()
    createNewAlbumAlert()
    newAlbumAlert.textFields![0].addTarget(self, action: #selector(editingChanged), for: .editingChanged)


//Core Data functions
func save(name: String) 
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else 
            return
    
    let managedContext =
        appDelegate.persistentContainer.viewContext
    let entity =
        NSEntityDescription.entity(forEntityName: "Album",
                                   in: managedContext)!
    let albumName = NSManagedObject(entity: entity,
                                    insertInto: managedContext)
    albumName.setValue(name, forKeyPath: "albumName")
    do 
        try managedContext.save()
        albums.append(albumName)
     catch let error as NSError 
        print("Could not save. \(error), \(error.userInfo)")
    
  

【问题讨论】:

【参考方案1】:

不要在myAlertController 上调用dismiss,而是在你的AlbumViewController 上调用dismiss。我在下面编辑了你的 textFieldShouldReturn 函数:

func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    let TFNameToSave = textField.text
    self.save(name: TFNameToSave!)
    self.albumCollectionView.reloadData()
    textField.resignFirstResponder()
    // ViewController should dismiss the alert controller
    dismiss(animated: true) 
        self.performSegue(withIdentifier: "segueForTF", sender: self)
        print("Album name has been inputted; return button tapped.")
    
    return true

来自the docs:

呈现视图控制器负责关闭视图 它呈现的控制器。

这里,presenting 视图控制器应该是AlbumViewControllerpresenting 应该是myAlertController

希望有效!

【讨论】:

警报控制器现在关闭,但没有执行 segue。这是我得到的错误:“警告:尝试在 上呈现 ,其视图不在窗口层次结构中!” @W.Cook 刚刚更新了我的答案,试试看(我添加了一个完成块,以便在警报解除后执行 segue) 太棒了,不用担心! :)

以上是关于在 Swift 中点击返回键时如何关闭 UIAlertController?的主要内容,如果未能解决你的问题,请参考以下文章

按下返回键时如何通过多个文本字段输入进行选项卡?

csharp 单击文本框的返回键时关闭键盘

Swift - 如何在文本字段之外点击后关闭数字键盘

按下 Enter 键时如何关闭 WPF 窗口(对话框)?

按下返回键时隐藏软键盘

点击文本字段右键时如何显示xib视图