208

With iOS 8.0, Apple introduced UIAlertController to replace UIActionSheet. Unfortunately, Apple didn't add any information on how to present it. I found an entry about it on hayaGeek's blog, however, it doesn't seem to work on iPad. The view is totally misplaced:

Misplaced: Misplaced image

Correct: enter image description here

I use the following code to show it on the interface:

    let alert = UIAlertController()
    // setting buttons
    self.presentModalViewController(alert, animated: true)

Is there another way to add it for iPad? Or did Apple just forget the iPad, or not implemented, yet?

4

13 回答 13

301

您可以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];

为 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
}
于 2014-06-15T20:42:31.513 回答
116

在 iPad 上,警报将使用新的UIPopoverPresentationController显示为弹出框,它要求您使用 sourceView 和 sourceRect 或 barButtonItem 为弹出框的呈现指定一个锚点

  • barButtonItem
  • 源视图
  • 源矩形

为了指定锚点,您需要获取对 UIAlertController 的 UIPopoverPresentationController 的引用并设置以下属性之一:

alertController.popoverPresentationController.barButtonItem = button;

示例代码:

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];
于 2014-09-04T06:31:47.610 回答
88

在 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)
}

如果您不设置演示者,您将在 iPad 上出现异常,-[UIPopoverPresentationController presentationTransitionWillBegin]并显示以下消息:

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

于 2015-11-15T23:50:09.080 回答
31

斯威夫特 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)

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

于 2020-02-25T21:06:01.753 回答
31

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")
    }
于 2017-11-12T04:04:10.410 回答
19

斯威夫特 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 = []
    }
  }
}

如何使用:

let actionSheetVC = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
addActionSheetForiPad(actionSheet: actionSheetVC)
present(actionSheetVC, animated: true, completion: nil)
于 2019-02-28T18:40:37.443 回答
16

2018 更新

由于这个原因,我刚刚拒绝了一个应用程序,一个非常快速的解决方案就是从使用操作表更改为警报。

发挥了魅力并顺利通过了 App Store 测试人员。

可能不是适合每个人的答案,但我希望这可以帮助你们中的一些人快速摆脱困境。

于 2018-06-18T11:48:49.033 回答
9

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

let alert = UIAlertController(title: nil, message: nil, preferredStyle: UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet)
于 2020-09-28T13:18:17.663 回答
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];
于 2014-10-05T21:02:48.180 回答
5

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

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}
于 2019-01-09T23:21:12.023 回答
2

只需在展示您的操作表之前添加以下代码:

if let popoverController = optionMenu.popoverPresentationController {
    popoverController.sourceView = self.view
    popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
    popoverController.permittedArrowDirections = []
}
于 2019-07-16T11:30:33.120 回答
1

它适用于 iphone 和 ipad

func showImagePicker() {
    var alertStyle = UIAlertController.Style.actionSheet
    if (UIDevice.current.userInterfaceIdiom == .pad) {
      alertStyle = UIAlertController.Style.alert
    }
    let alert = UIAlertController(title: "", message: "Upload Attachment", preferredStyle: alertStyle)
    alert.addAction(UIAlertAction(title: "Choose from gallery", style: .default , handler:{ (UIAlertAction) in
        self.pickPhoto(sourceType: .photoLibrary)
    }))
    alert.addAction(UIAlertAction(title: "Take Photo", style: .default, handler:{ (UIAlertAction) in
        self.pickPhoto(sourceType: .camera)
    }))
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler:{ (UIAlertAction) in
    }))
    present(alert, animated: true, completion: nil)
}
于 2021-02-09T12:41:30.280 回答
0

如果您的代码库同时支持 iPhone 和 iPad 设备,请考虑以下

present(_ viewControllerToPresent:animated:completion:)在以下情况下定期使用:

  • 呈现一个UIAlertControllerwith preferredStyleof.alert
  • 提出UIViewController一个.modalPresentationStyle
    • .overFullScreen
    • .formSheet
    • .automatic 如果modalPresentationStyle未指定默认值
    • .currentContext
    • .fullScreen
    • .custom
    • .overCurrentContext

在以下情况下配置popoverPresentationController'ssourceRectsourceView呈现之前:

  • 呈现一个UIAlertControllerwith preferredStyleof.actionSheet
  • 提出UIViewController一个.modalPresentationStyle
    • .popover
    • .none 这将在 iPhone 和 iPad 上崩溃,并显示错误“指定的模式演示样式没有相应的演示控制器”。
  • 呈现一个UIActivityViewController(基于https://developer.apple.com/documentation/uikit/uiactivityviewcontroller“在 iPad 上,您必须在弹出窗口中呈现视图控制器。在 iPhone 和 iPod touch 上,您必须以模态方式呈现它。”

下面是一个配置示例popoverPresentationController

if let popoverController = popoverPresentationController {
  popoverController.sourceView = view
  popoverController.sourceRect = CGRect(x: view.bounds.maxX, y: 40, width: 0, height: 0)
}

如果您发现此处未列出的任何其他案例,请告诉我!

于 2021-12-30T22:21:41.417 回答