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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24224916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:54:30  来源:igfitidea点击:

Presenting a UIAlertController properly on an iPad using iOS 8

iosipaduser-interfaceuialertcontroller

提问by Matt3o12

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

在 iOS 8.0 中,Apple 引入了UIAlertController来替换UIActionSheet。不幸的是,Apple 没有添加任何有关如何呈现它的信息。我在 hayaGeek 的博客上找到了有关它的条目,但是,它似乎不适用于 iPad。该视图完全放错了位置:

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?

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

回答by Peter Hajas

You can present a UIAlertControllerfrom a popover by using UIPopoverPresentationController.

您可以UIAlertController使用UIPopoverPresentationController.

In Obj-C:

在 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];

Editing for Swift 4.2, though there are many blogs available for the same but it may save your time to go and search for them.

为 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
            }

回答by Sabareesh

On iPad the alert will be displayed as a popover using the new UIPopoverPresentationController, it requires that you specify an anchor point for the presentation of the popover using either a sourceView and sourceRect or a barButtonItem

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

  • barButtonItem
  • sourceView
  • sourceRect
  • 条形按钮项
  • 源视图
  • 源矩形

In order to specify the anchor point you will need to obtain a reference to the UIAlertController's UIPopoverPresentationController and set one of the properties as follows:

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

alertController.popoverPresentationController.barButtonItem = button;

sample code:

示例代码:

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];

回答by kviksilver

In Swift 2, you want to do something like this to properly show it on iPhone and iPad:

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

If you don't set the presenter, you will end up with an exception on iPad in -[UIPopoverPresentationController presentationTransitionWillBegin]with the following message:

如果您不设置演示者,您将在 iPad-[UIPopoverPresentationController presentationTransitionWillBegin]上看到以下消息的异常:

Fatal Exception: NSGenericException Your application has presented a UIAlertController (<UIAlertController: 0x17858a00>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.

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

回答by iAj

Update for Swift 3.0 and higher

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

回答by SongBox

2018 Update

2018 更新

I just had an app rejected for this reason and a very quick resolution was simply to change from using an action sheet to an alert.

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

Worked a charm and passed the App Store testers just fine.

很有魅力,并通过了 App Store 测试人员。

May not be a suitable answer for everyone but I hope this helps some of you out of a pickle quickly.

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

回答by Siddhesh Mahadeshwar

Swift 4 and above

Swift 4 及以上

I have created an extension

我创建了一个扩展

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 = []
    }
  }
}

How to use:

如何使用:

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

回答by Serge Gerasimenko

Here's a quick solution:

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

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];

回答by Greg T

Swift 5

斯威夫特 5

I used "actionsheet" style for iPhone and "alert" for iPad. iPad displays in the center of the screen. No need to specify sourceView or anchor the view anywhere.

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

Edit: Per ShareToD's suggestion, updated deprecated "UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad" check

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

回答by Caption Newt

Just add the following code before presenting your action sheet:

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

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 = []
}

回答by Matthew Becker

For me I just needed to add the following:

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

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}