在 Swift 中点击 return 键时,如何关闭 UIAlertController?
How do I dismiss a UIAlertController when the return key is tapped in Swift?
我有一个带有两个按钮和一个文本字段的 UIAlertController。当保存按钮被点击时,一个 segue 被执行。我还在 textFieldShouldReturn
中设置了 return 键来执行此操作。但是,当 return 键被点击时,警报控制器不会关闭。它向上移动到视图的左上角,并导致动画在返回视图时挂起。我还尝试使用 myAlertController.dismiss(animated: false, completion: nil)
关闭警报控制器,但这会引发 "Attempt to present a UINavigationController on a UIAlertController whose view is not in the window hierarchy" 错误。当 return 键被点击并仍然执行 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)")
}
}
}
不要在 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:
The presenting view controller is responsible for dismissing the view
controller it presented.
在这里,presenting view controller 应该是 AlbumViewController
而 presented 是 myAlertController
.
希望有用!
我有一个带有两个按钮和一个文本字段的 UIAlertController。当保存按钮被点击时,一个 segue 被执行。我还在 textFieldShouldReturn
中设置了 return 键来执行此操作。但是,当 return 键被点击时,警报控制器不会关闭。它向上移动到视图的左上角,并导致动画在返回视图时挂起。我还尝试使用 myAlertController.dismiss(animated: false, completion: nil)
关闭警报控制器,但这会引发 "Attempt to present a UINavigationController on a UIAlertController whose view is not in the window hierarchy" 错误。当 return 键被点击并仍然执行 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)")
}
}
}
不要在 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:
The presenting view controller is responsible for dismissing the view controller it presented.
在这里,presenting view controller 应该是 AlbumViewController
而 presented 是 myAlertController
.
希望有用!