Präsentieren eines UIAlertControllers auf einem iPad unter iOS 8

194

Mit iOS 8.0 führte Apple UIAlertController ein , um UIActionSheet zu ersetzen . Leider hat Apple keine Informationen zur Präsentation hinzugefügt. Ich habe einen Eintrag darüber in hayaGeeks Blog gefunden, aber es scheint nicht auf dem iPad zu funktionieren. Die Ansicht ist völlig fehl am Platz:

Verlegt: Falsch platziertes Bild

Richtig: Geben Sie hier die Bildbeschreibung ein

Ich benutze den folgenden Code, um ihn auf der Oberfläche anzuzeigen:

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

Gibt es eine andere Möglichkeit, es für das iPad hinzuzufügen? Oder hat Apple das iPad einfach vergessen oder noch nicht implementiert?

Matt3o12
quelle

Antworten:

284

Sie können UIAlertControllerein Popover mithilfe von anzeigen UIPopoverPresentationController.

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

Bearbeiten für Swift 4.2, obwohl es viele Blogs für dasselbe gibt, aber es kann Ihre Zeit sparen, nach ihnen zu suchen.

 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
            }
Peter Hajas
quelle
Verwenden Sie [alertController.view setTintColor: [UIColor blackColor]]; wenn Sie den Text nicht sehen. UIAlertController verwendet standardmäßig die Farbtönung des Fensters, die in diesem Beispiel weiß und unsichtbar sein kann.
Whyoz
2
Die Schaltfläche Abbrechen wird auf dem iPad nicht
angezeigt
14
@ BhavinRamani Abbrechen-Schaltflächen werden automatisch aus Popovers entfernt, da das Tippen außerhalb des Popovers in einem Popover-Kontext "Abbrechen" bedeutet.
Christopherdrum
Das ist großartig, mein Problem ist gelöst! ich danke dir sehr!
Mahir Tayir
109

Auf dem iPad wird die Warnung mit dem neuen UIPopoverPresentationController als Popover angezeigt. Dazu müssen Sie einen Ankerpunkt für die Darstellung des Popovers mithilfe von sourceView und sourceRect oder barButtonItem angeben

  • barButtonItem
  • sourceView
  • sourceRect

Um den Ankerpunkt anzugeben, müssen Sie einen Verweis auf den UIPopoverPresentationController des UIAlertController erhalten und eine der folgenden Eigenschaften festlegen:

alertController.popoverPresentationController.barButtonItem = button;

Beispielcode:

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];
Sabareesh
quelle
28
Es ist nicht "eine der drei" Ankerpunkteigenschaften; es ist: "entweder ein sourceView und sourceRect oder ein barButtonItem".
Rolleric
2
+1 für Rolleric. In der Dokumentation von Apple heißt es zu sourceRect: "Verwenden Sie diese Eigenschaft in Verbindung mit der sourceView-Eigenschaft, um den Ankerort für das Popover anzugeben. Alternativ können Sie den Ankerort für das Popover mithilfe der Eigenschaft barButtonItem angeben." - developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Ben Patch
Oh Mann. Es ist nur ohne Protokollmeldung abgestürzt. Warum sollte nicht zumindest eine Warnung zur Kompilierungszeit (für universelle Apps) angezeigt werden?
Mike Keskinov
84

In Swift 2 möchten Sie so etwas tun, um es auf iPhone und iPad richtig anzuzeigen:

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

Wenn Sie den Präsentator nicht einstellen, wird auf dem iPad eine Ausnahme -[UIPopoverPresentationController presentationTransitionWillBegin]mit der folgenden Meldung angezeigt:

Schwerwiegende Ausnahme: NSGenericException Ihre Anwendung hat einen UIAlertController (<UIAlertController: 0x17858a00>) im Stil UIAlertControllerStyleActionSheet angezeigt. Der modalPresentationStyle eines UIAlertControllers mit diesem Stil ist UIModalPresentationPopover. Sie müssen Standortinformationen für dieses Popover über den popoverPresentationController des Alert-Controllers bereitstellen. Sie müssen entweder ein sourceView und sourceRect oder ein barButtonItem angeben. Wenn diese Informationen bei der Präsentation des Alert-Controllers nicht bekannt sind, können Sie sie in der UIPopoverPresentationControllerDelegate-Methode -prepareForPopoverPresentation bereitstellen.

kviksilver
quelle
26

Update für Swift 3.0 und höher

    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")
    }
iAj
quelle
Ich verwende eine Schublade. Ich versuche, die angegebene Lösung zu verwenden, bin jedoch fehlgeschlagen.
Rana Ali Waseem
Ich habe keinen Code, weil ich das Aktionsblatt entferne und den Alarm verwende. Aber in meinem Code war nur eine Zeile anders. Lassen Sie actionSheet = UIAlertController (Titel: "" ,, Nachricht: "", PreferredStyle: .actionSheet). Aber ich erinnere mich an die Protokolle. Es stürzte aufgrund einer Schublade ab. Ich denke, dass die Schublade nicht geöffnet werden kann Aktionsblatt. weil es sich in der linken Ecke des Bildschirms öffnete. Problem war nur am iPad.
Rana Ali Waseem
15

Update 2018

Ich hatte gerade eine App aus diesem Grund abgelehnt und eine sehr schnelle Lösung bestand darin, einfach von der Verwendung eines Aktionsblatts zu einer Warnung zu wechseln.

Hat einen Zauber gewirkt und die App Store-Tester ganz gut bestanden.

Vielleicht nicht für jeden eine passende Antwort, aber ich hoffe, dies hilft einigen von Ihnen schnell aus der Essiggurke.

SongBox
quelle
1
Funktionierte perfekt auf iPad und iPhone - Danke
Jeremy Andrews
Es ist nicht die beste Lösung. Manchmal möchten Sie den modernen ActionSheet-Stil verwenden.
ShadeToD
9

Swift 4 und höher

Ich habe eine Erweiterung erstellt

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

Wie benutzt man:

let actionSheetVC = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
addActionSheetForIpad(actionSheet: actionSheetVC)
present(actionSheetVC, animated: true, completion: nil)
Siddhesh Mahadeshwar
quelle
Ich versuche es, kann aber func addActionSheerForiPad in xcode 11.2.1
Rana Ali Waseem
@RanaAliWaseem rufst du das in der UIViewController-Klasse auf?
ShadeToD
Ja. Ich nenne es in der UIViewController-Klasse. Es wird jedoch mit einer Basisklasse und einer Basisklasse geerbt, die von UIViewController geerbt wurden.
Rana Ali Waseem
8

Hier ist eine schnelle Lösung:

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];
Serge Gerasimenko
quelle
3
Diese Frage bezieht sich auf UIAlertController, nicht auf UIActivityViewController
Roman Truba
Können Sie die Antwort für Swift 3 zusammen mit UIActivityViewController aktualisieren?
Dia
7

Swift 5

Ich habe den "Actionsheet" -Stil für das iPhone und den "Alarm" für das iPad verwendet. Das iPad wird in der Mitte des Bildschirms angezeigt. Sie müssen sourceView nicht angeben oder die Ansicht an einer beliebigen Stelle verankern.

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

let alertController = UIAlertController(title: "Your title", message: nil, preferredStyle: alertStyle)

Bearbeiten: Gemäß dem Vorschlag von ShareToD wurde die veraltete Prüfung "UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiom.pad" aktualisiert

Greg T.
quelle
2
In iOS 13 war 'UI_USER_INTERFACE_IDIOM ()' in iOS 13.0 veraltet: Verwenden Sie - [UIDevice userInterfaceIdiom] direkt. Sie sollten es in UIDevice.current.userInterfaceIdiom == .pad
ShadeToD
2

Für mich musste ich nur Folgendes hinzufügen:

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}
Matthew Becker
quelle
2
Sie können die if-Anweisung weglassen und die optionale Verkettung verwenden: alertController.popoverPresentationController? .BarButtonItem = navigationItem.rightBarButtonItem
Dale
2

Fügen Sie einfach den folgenden Code hinzu, bevor Sie Ihr Aktionsblatt präsentieren:

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