iOS 8を使用するiPadでUIAlertControllerを適切に表示する


194

iOS 8.0では、AppleはUIActionSheetを置き換えるUIAlertControllerを導入しました。残念ながら、アップルはそれを提示する方法についての情報を追加しませんでした。hayaGeekのブログでそのエントリを見つけましたが、iPadでは動作しないようです。ビューは完全に間違っています:

紛失: 間違った画像

正しい: ここに画像の説明を入力してください

次のコードを使用して、インターフェイスに表示します。

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

iPadに追加する別の方法はありますか?それともAppleはiPadを忘れたか、実装されていませんか?

回答:


284

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
            }

[alertController.view setTintColor:[UIColor blackColor]]を使用します。テキストが表示されない場合。UIAlertControllerはデフォルトでウィンドウのティントカラーを使用します。この例では、これは白で見えない場合があります。
Whyo​​z 2014年

2
iPadにキャンセルボタンが表示されない
Bhavin Ramani 2016

14
ポップオーバーのコンテキストでは、ポップオーバーの外側をタップすると「キャンセル」を表すため、@ BhavinRamaniキャンセルボタンはポップオーバーから自動的に削除されます。
クリストファードラム

これは素晴らしいです、私の問題は解決しました!どうもありがとうございます!
Mahir Tayir、

109

iPadでは、アラートは新しいUIPopoverPresentationControllerを使用してポップオーバーとして表示され、sourceViewとsourceRectまたはbarButtonItemのいずれかを使用して、ポップオーバーのプレゼンテーションのアンカーポイントを指定する必要があります。

  • barButtonItem
  • sourceView
  • sourceRect

アンカーポイントを指定するには、UIAlertControllerのUIPopoverPresentationControllerへの参照を取得し、プロパティの1つを次のように設定する必要があります。

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

28
「3つのうちの1つ」のアンカーポイントプロパティではありません。「sourceViewおよびsourceRectまたはbarButtonItemのいずれか」です。
Rolleric

2
Rollericの+1。Appleのドキュメントには、sourceRectに関する記述があります。「このプロパティをsourceViewプロパティと組み合わせて使用​​して、ポップオーバーのアンカー位置を指定します。代わりに、barButtonItemプロパティを使用してポップオーバーのアンカー位置を指定できます。」- developer.apple.com/library/prerelease/ios/documentation/UIKit/...
ベン・パッチ

ちょっと、あなた。ログメッセージなしでクラッシュしました。(ユニバーサルアプリの場合)少なくともコンパイル時の警告を表示しないのはなぜですか?
マイク・ケスキノフ

85

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アプリケーションが、UIAlertControllerStyleActionSheetスタイルのUIAlertController(<UIAlertController:0x17858a00>)を提示しました。このスタイルのUIAlertControllerのmodalPresentationStyleは、UIModalPresentationPopoverです。警告コントローラーのpopoverPresentationControllerを介して、このポップオーバーの位置情報を提供する必要があります。sourceViewとsourceRect、またはbarButtonItemのいずれかを提供する必要があります。アラートコントローラを提示するときにこの情報がわからない場合は、UIPopoverPresentationControllerDelegateメソッド-prepareForPopoverPresentationで提供できます。


26

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

引き出しを使用していますが、指定されたソリューションを使用しようとしましたが失敗しました。
Rana Ali Waseem

アクションシートを削除してアラートを使用しているため、コードはありません。しかし、私のコードでは1行だけが異なっていましたlet actionSheet = UIAlertController(title: "" ,, message: ""、preferredStyle:.actionSheet)しかし、ログを覚えていますアクションシート。画面の左隅に開いていたからです。問題はiPadのみでした。
Rana Ali Waseem

15

2018年アップデート

この理由でアプリが拒否されました。非常に迅速な解決策は、アクションシートの使用からアラートに変更することでした。

魅力的に機能し、App Storeテスターに​​問題なく合格しました。

誰にとっても適切な答えではないかもしれませんが、これがあなたの何人かがピクルスからすぐに役立つことを願っています。


1
iPadとiPhoneの両方で完全に動作しました-おかげで
ジェレミーアンドリュース

それは最善の解決策ではありません。モダンなactionSheetスタイルを使用したい場合があります。
ShadeToD

9

Swift 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)

私は試してみましたが、xcode 11.2.1でfunc addActionSheerForiPadを呼び出すことができません
Rana Ali Waseem

@RanaAliWaseemはこれをUIViewControllerクラス内で呼び出していますか?
ShadeToD

はい。UIViewControllerクラスで呼び出します。しかし、それはBaseクラスで継承され、Base ClassはUIViewControllerから継承されます。
Rana Ali Waseem

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

3
この質問はUIAlertController、ないUIActivityViewControllerについてです
ローマTruba

UIActivityViewControllerと共にSwift 3の回答を更新できますか?
Dia

7

スウィフト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」チェックを更新


2
iOS 13では、「UI_USER_INTERFACE_IDIOM()」はiOS 13.0で廃止されました:-[UIDevice userInterfaceIdiom]を直接使用します。UIDevice.current.userInterfaceIdiom == .pad
ShadeToD

2

私にとっては、私は以下を追加する必要があるだけです:

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

2
ifステートメントを省略して、オプションのチェーンを使用できます。alertController.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
Dale

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 = []
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.