使用iOS 8在iPad上正确呈现UIAlertController

Mat*_*o12 186 user-interface ipad ios uialertcontroller

在iOS 8.0中,Apple引入了UIAlertController来取代UIActionSheet.不幸的是,Apple没有添加任何有关如何呈现它的信息.我在hayaGeek的博客上找到了一个关于它的条目,然而,它似乎不适用于iPad.视图完全错位:

放错了地方: 错位的图像

正确: 在此输入图像描述

我使用以下代码在界面上显示它:

    let alert = UIAlertController()
    // setting buttons
    self.presentModalViewController(alert, animated: true)
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以将它添加到iPad吗?或者苹果只是忘了iPad,还是没有实现?

Pet*_*jas 269

您可以UIAlertController使用弹出来自弹出窗口UIPopoverPresentationController.

在Obj-C中:

UIViewController *self; // code assumes you're in a view controller
UIButton *button; // the button you want to show the popup sheet from

UIAlertController *alertController;
UIAlertAction *destroyAction;
UIAlertAction *otherAction;

alertController = [UIAlertController alertControllerWithTitle:nil
                                                      message:nil
                           preferredStyle:UIAlertControllerStyleActionSheet];
destroyAction = [UIAlertAction actionWithTitle:@"Remove All Data"
                                         style:UIAlertActionStyleDestructive
                                       handler:^(UIAlertAction *action) {
                                           // do destructive stuff here
                                       }];
otherAction = [UIAlertAction actionWithTitle:@"Blah"
                                       style:UIAlertActionStyleDefault
                                     handler:^(UIAlertAction *action) {
                                         // do something here
                                     }];
// note: you can control the order buttons are shown, unlike UIActionSheet
[alertController addAction:destroyAction];
[alertController addAction:otherAction];
[alertController setModalPresentationStyle:UIModalPresentationPopover];

UIPopoverPresentationController *popPresenter = [alertController 
                                              popoverPresentationController];
popPresenter.sourceView = button;
popPresenter.sourceRect = button.bounds;
[self presentViewController:alertController animated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)

编辑Swift 4.2,虽然有很多博客可用,但它可以节省您的时间去搜索它们.

 if let popoverController = yourAlert.popoverPresentationController {
                popoverController.sourceView = self.view //to set the source of your alert
                popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement.
                popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction
            }
Run Code Online (Sandbox Code Playgroud)

  • @BhavinRamani取消按钮会自动从弹出框中删除,因为在弹出窗口中弹出弹出窗口代表"取消". (12认同)
  • iPad 中未显示取消按钮 (3认同)

Sab*_*esh 104

在iPad上,警报将使用新的UIPopoverPresentationController显示为弹出窗口,它要求您使用sourceView和sourceRect或barButtonItem为弹出窗口的表示指定锚点

  • barButtonItem
  • sourceView
  • sourceRect

为了指定的锚点,您将需要获得参考UIAlertController的UIPopoverPresentationController并设置属性之一,如下所示:

alertController.popoverPresentationController.barButtonItem = button;
Run Code Online (Sandbox Code Playgroud)

示例代码:

UIAlertAction *actionDelete = nil;
UIAlertAction *actionCancel = nil;

// create action sheet
UIAlertController *alertController = [UIAlertController
                                      alertControllerWithTitle:actionTitle message:nil
                                      preferredStyle:UIAlertControllerStyleActionSheet];

// Delete Button
actionDelete = [UIAlertAction
                actionWithTitle:NSLocalizedString(@"IDS_LABEL_DELETE", nil)
                style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

                    // Delete
                    // [self deleteFileAtCurrentIndexPath];
                }];

// Cancel Button
actionCancel = [UIAlertAction
                actionWithTitle:NSLocalizedString(@"IDS_LABEL_CANCEL", nil)
                style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                    // cancel
                    // Cancel code
                }];

// Add Cancel action
[alertController addAction:actionCancel];
[alertController addAction:actionDelete];

// show action sheet
alertController.popoverPresentationController.barButtonItem = button;
alertController.popoverPresentationController.sourceView = self.view;

[self presentViewController:alertController animated:YES
                 completion:nil];
Run Code Online (Sandbox Code Playgroud)

  • 它不是"三个"锚点属性之一; 它是:"sourceView和sourceRect或barButtonItem". (26认同)
  • +1为Rolleric。Apple的文档指出了有关sourceRect的信息:“将此属性与sourceView属性一起使用以指定弹出窗口的锚点位置。或者,您可以使用barButtonItem属性为弹出窗口指定锚点位置。” -https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIPopoverPresentationController_class/index.html#//apple_ref/occ/instp/UIPopoverPresentationController/sourceRect (2认同)

kvi*_*ver 81

在Swift 2中,你想做这样的事情来在iPhone和iPad上正确显示它:

func confirmAndDelete(sender: AnyObject) {
    guard let button = sender as? UIView else {
        return
    }

    let alert = UIAlertController(title: NSLocalizedString("Delete Contact?", comment: ""), message: NSLocalizedString("This action will delete all downloaded audio files.", comment: ""), preferredStyle: .ActionSheet)
    alert.modalPresentationStyle = .Popover

    let action = UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .Destructive) { action in
        EarPlaySDK.deleteAllResources()
    }
    let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel) { action in

    }
    alert.addAction(cancel)
    alert.addAction(action)

    if let presenter = alert.popoverPresentationController {
        presenter.sourceView = button
        presenter.sourceRect = button.bounds
    }
    presentViewController(alert, animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)

如果您未设置演示者,则最终会在iPad上出现例外-[UIPopoverPresentationController presentationTransitionWillBegin]消息,并显示以下消息:

致命异常:NSGenericException您的应用程序提供了样式UIAlertControllerStyleActionSheet的UIAlertController(<UIAlertController:0x17858a00>).具有此样式的UIAlertController的modalPresentationStyle是UIModalPresentationPopover.您必须通过警报控制器的popoverPresentationController为此弹出窗口提供位置信息.您必须提供sourceView和sourceRect或barButtonItem.如果在显示警报控制器时未知此信息,则可以在UIPopoverPresentationControllerDelegate方法-prepareForPopoverPresentation中提供该信息.


Gre*_*g T 28

斯威夫特 5

我在 iPhone 上使用了“actionsheet”样式,在 iPad 上使用了“alert”样式。iPad 显示在屏幕中央。无需在任何地方指定 sourceView 或锚定视图。

var alertStyle = UIAlertController.Style.actionSheet
if (UIDevice.current.userInterfaceIdiom == .pad) {
  alertStyle = UIAlertController.Style.alert
}

let alertController = UIAlertController(title: "Your title", message: nil, preferredStyle: alertStyle)
Run Code Online (Sandbox Code Playgroud)

编辑:根据 ShareToD 的建议,更新已弃用的“UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad”检查

  • 在 iOS 13 中“UI_USER_INTERFACE_IDIOM()”在 iOS 13.0 中已弃用:直接使用 -[UIDevice userInterfaceIdiom]。您应该将其更改为 UIDevice.current.userInterfaceIdiom == .pad (2认同)

iAj*_*iAj 23

更新Swift 3.0及更高版本

    let actionSheetController: UIAlertController = UIAlertController(title: "SomeTitle", message: nil, preferredStyle: .actionSheet)

    let editAction: UIAlertAction = UIAlertAction(title: "Edit Details", style: .default) { action -> Void in

        print("Edit Details")
    }

    let deleteAction: UIAlertAction = UIAlertAction(title: "Delete Item", style: .default) { action -> Void in

        print("Delete Item")
    }

    let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in }

    actionSheetController.addAction(editAction)
    actionSheetController.addAction(deleteAction)
    actionSheetController.addAction(cancelAction)

//        present(actionSheetController, animated: true, completion: nil)   // doesn't work for iPad

    actionSheetController.popoverPresentationController?.sourceView = yourSourceViewName // works for both iPhone & iPad

    present(actionSheetController, animated: true) {
        print("option menu presented")
    }
Run Code Online (Sandbox Code Playgroud)


Son*_*Box 14

2018年更新

由于这个原因我只是拒绝了一个应用程序,并且一个非常快速的解决方案只是从使用操作表变为警报.

工作了一个魅力,并通过App Store测试员就好了.

对于每个人来说可能不是一个合适的答案,但我希望这可以帮助你们中的一些人迅速摆脱困境.


cra*_*aft 9

雨燕5

适用于 iPad 和 iPhone。

悬停在按钮下方的操作表

对于 iPhone,操作表将正常显示,iPad 将显示在按钮下方。

actionSheet.popoverPresentationController?.sourceView = fooButton
actionSheet.popoverPresentationController?.sourceRect = fooButton.bounds
Run Code Online (Sandbox Code Playgroud)
屏幕/视图中间的操作表

对于 iPhone,操作表将正常显示,iPad 将显示在屏幕/视图的中间。

actionSheet.popoverPresentationController?.sourceView = view
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
actionSheet.popoverPresentationController?.permittedArrowDirections = []
Run Code Online (Sandbox Code Playgroud)


小智 8

这是一个快速的解决方案:

NSString *text = self.contentTextView.text;
NSArray *items = @[text];

UIActivityViewController *activity = [[UIActivityViewController alloc]
                                      initWithActivityItems:items
                                      applicationActivities:nil];

activity.excludedActivityTypes = @[UIActivityTypePostToWeibo];

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
    //activity.popoverPresentationController.sourceView = shareButtonBarItem;

    activity.popoverPresentationController.barButtonItem = shareButtonBarItem;

    [self presentViewController:activity animated:YES completion:nil];

}
[self presentViewController:activity animated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)

  • 这个问题是关于UIAlertController,而不是UIActivityViewController (3认同)

Sid*_*war 6

快速4及以上

我创建了一个扩展

extension UIViewController {
  public func addActionSheetForiPad(actionSheet: UIAlertController) {
    if let popoverPresentationController = actionSheet.popoverPresentationController {
      popoverPresentationController.sourceView = self.view
      popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
      popoverPresentationController.permittedArrowDirections = []
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如何使用:

let actionSheetVC = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
addActionSheetForIpad(actionSheet: actionSheetVC)
present(actionSheetVC, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)


小智 6

Swift 4.2 你可以使用这样的条件:

let alert = UIAlertController(title: nil, message: nil, preferredStyle: UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet)
Run Code Online (Sandbox Code Playgroud)


小智 5

对我来说,我只需要添加以下内容:

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以省略 if 语句并使用可选链接: alertController.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem (3认同)