Отобразить UIAlertController из класса UIView/NSObject
У меня working iOS application
Для support iOS8
я заменяю UIAlertView/UIActionSheet with
UIAlertController
.
Проблема:
Для отображения UIAlertController мне нужен presentViewController
метод класса UIViewController.
Но UIAlertView отображает из классов inherited
от
UIView or NSObject
,
Я не могу получить метод [self presentViewController...]
по понятной причине.
Моя работа:
Я попытался получить текущее окно формы rootViewController и отобразить UIAlertController.
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]
но имеют некоторые проблемы с вращением, например, если у моего текущего контроллера вида нет поддержки вращения
он будет вращаться, если открыт UIAlertController.
Вопрос:
Кто-нибудь сталкивался с такой же проблемой и имел безопасное решение?
если да, пожалуйста, предоставьте мне пример или дайте какой-нибудь справочник
Ответы
Ответ 1
Похоже, что вы в настоящий момент (pre-iOS8) запускаете представление предупреждения из объекта просмотра. Эта довольно плохая практика, так как в общем случае предупреждения должны быть вызваны действиями и логикой. И этот код должен жить в контроллерах.
Я предлагаю вам реорганизовать ваш текущий код, чтобы переместить логику, которая запускает предупреждение на правильный контроллер, а затем вы можете легко перейти на iOS 8, используя self
в качестве контроллера.
Если вместо этого вы вызываете предупреждение из внешнего объекта, то передайте его контроллеру методу, вызывающему предупреждение. Где-то вверх по течению вы должны знать о контроллере.
Ответ 2
Сегодня я решил практически такую же проблему. Как Jageen, я столкнулся с ситуацией, когда хотел представить UIAlertController, но из класса, отличного от UIViewController. В моем случае я хотел, чтобы появилось предупреждение, когда выполняется блок отказа HTTP-запроса.
Это то, что я использовал, и в отличие от нашего друга здесь, он отлично работал у меня.
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
Ответ 3
Лучшее решение для классов UIView
ниже
ObjectiveC
UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController.........
- (UIViewController *)currentTopViewController
{
UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
while (topVC.presentedViewController)
{
topVC = topVC.presentedViewController;
}
return topVC;
}
Swift
var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
Ответ 4
Мое решение ниже:
Swift
class alert {
func msg(message: String, title: String = "")
{
let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil)
}
}
Вот пример использования:
let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
Ответ 5
У меня была ситуация, когда в subview есть кнопка, чтобы отклонить ее. Представляю предупреждение для подтверждения действия. Он отправляет сообщение делегату - который является контроллером представления, содержащим subview - для удаления subview
Первоначально я представил UIAlertView из UIView. Рефакторинг для UIAlertController, так как UIAlertController не может представить себя как UIAlertView can, я придумал следующее (в Swift, легко переведенное на ObjC):
Добавить протокол в подвью:
protocol MySubviewDelegate {
// called when user taps subview/delete button
// or, you could call it from a gesture handler, etc.
func displayAlert(alert : UIAlertController)
// called when user confirms delete from the alert controller
func shouldRemoveSubview(sender : AnyObject)
}
Добавьте делегата для подзаголовка и добавьте обработчик для нажатия кнопки/жестов:
class MySubview : UIView {
var subviewDelegate : MySubviewDelegate!
...
func handleTap(sender : AnyObject) {
// set up the alert controller here
var alert = UIAlertController(title: "Confirm Delete",
message: "This action is permanent. Do you wish to continue?",
preferredStyle: UIAlertControllerStyle.Alert)
// Cancel action
// nil handler means "no action if Cancel button selected"
alert.addAction(UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.Cancel,
handler: nil))
// Confirm action
alert.addAction(UIAlertAction(title: "Confirm",
style: UIAlertActionStyle.Default,
handler: { (action : UIAlertAction!) -> Void in
// call delegate method to perform confirmed action, - i.e. remove
self.subviewDelegate.shouldRemoveSubview(self)
}))
// call delegate method to display alert controller
// send alert object to delegate
self.subviewDelegate.displayAlert(alert)
}
}
Установите вызывающий UIViewController в качестве делегата subview, например, в свой метод viewDidLoad(), и включите методы протокола:
class viewController : UIViewController, MySubviewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.subviewDelegate = self
...
}
func displayAlert(alert : UIAlertController) {
presentViewController(alert, animated: true, completion: nil)
}
func shouldRemoveSubview(sender : AnyObject) {
// cast as UIView / MySubview subclass
var subview = sender as MySubview
// remove the subview / perform the desired action
subview.removeFromSuperview()
...
}
...
}
Это позволяет избежать необходимости находить самый верхний контроллер представлений или передавать ссылки на контроллеры представлений в subviews (кроме отношения к объекту/делегату).
Ответ 6
В Swift 3:
UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
Ответ 7
У меня была эта проблема. См. Мой SO ответ для кода, чтобы получить самый верхний контроллер представлений, с помощью которого можно представить другой контроллер представления.
Я согласен, что в большинстве случаев плохой практикой является представление контроллера представления из объекта, который не является контроллером представления, но иногда вам нужно.
Ответ 8
Для отображения UIAlertController в классе NSObject используйте код ниже.
UIAlertController * popup = [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
[popup dismissViewControllerAnimated:YES completion:nil];
}];
[popup addAction:cancel];
UIViewController *rootViewController = [[Helper shareInstance] topViewController];
[rootViewController presentViewController:popup animated:YES completion:nil];
//Поместите метод ниже в свой глобальный класс помощников.
- (UIViewController *)topViewController {
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewController:(UIViewController *)rootViewController {
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
Ответ 9
В общем случае предупреждения должны обрабатываться в контроллере представления. Вот пример требуемого кода:
Swift 3
private func displayError(message: String) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
alertController.addAction(okayAction)
present(alertController, animated: true, completion: nil)
}