İOS 8 kullanan bir iPad'de UIAlertController'ı düzgün bir şekilde sunma


197

Apple, iOS 8.0 ile UIActionSheet'in yerini alacak UIAlertController'ı tanıttı . Ne yazık ki Apple, bunu nasıl sunacağına dair herhangi bir bilgi eklemedi. HayaGeek'in blogunda bununla ilgili bir giriş buldum , ancak iPad'de çalışmıyor gibi görünüyor. Görüş tamamen yanlış yerleştirilmiş:

Yanlış yerleştirilmiş: Yanlış yerleştirilmiş görüntü

Doğru: görüntü açıklamasını buraya girin

Arayüzde göstermek için aşağıdaki kodu kullanıyorum:

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

İPad için eklemenin başka bir yolu var mı? Veya Apple iPad'i unuttu mu yoksa henüz uygulanmadı mı?

Yanıtlar:


291

UIAlertControllerKullanarak bir açılır pencereden sunum yapabilirsiniz UIPopoverPresentationController.

Obj-C'de:

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 için düzenleme, ancak aynı için pek çok blog var ama gidip onları aramak için zaman kazandırabilir.

 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]] kullanın; metni görmüyorsanız. UIAlertController, varsayılan olarak pencerenin ton rengini kullanır; bu, bu örnekte beyaz ve görünmez olabilir.
whyoz

2
İptal düğmesi iPad'de görüntülenmiyor
Bhavin Ramani

15
@BhavinRamani İptal düğmeleri, açılır pencerelerden otomatik olarak kaldırılır, çünkü açılır bilgi penceresinin dışına dokunmak, açılır bilgi içeriğinde "iptal" anlamına gelir.
christopherdrum

bu harika, sorunum çözüldü! çok teşekkür ederim!
Mahir Tayir

109

İPad'de uyarı yeni kullanılarak popover olarak gösterilecektir UIPopoverPresentationController , bu ya bir sourceView ve sourceRect veya barButtonItem kullanarak popover sunumu için bir çapa noktası belirtin gerektirir

  • barButtonItem
  • sourceView
  • sourceRect

Bağlantı noktasını belirlemek için, UIAlertController'ın UIPopoverPresentationController'ına bir referans almanız ve özelliklerden birini aşağıdaki gibi ayarlamanız gerekir:

alertController.popoverPresentationController.barButtonItem = button;

basit kod:

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
"Üç" bağlantı noktası özelliğinden biri değildir; bu: "bir sourceView ve sourceRect veya bir barButtonItem".
Rolleric

2
Rolleric için +1. Apple'ın belgeleri sourceRect ile ilgili şunları belirtir: "Açılır bilgi penceresinin bağlantı konumunu belirtmek için bu özelliği sourceView özelliğiyle birlikte kullanın. Alternatif olarak, barButtonItem özelliğini kullanarak açılır pencere için bağlantı konumunu belirtebilirsiniz." - developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Ben Patch

Oh, adamım. Herhangi bir günlük mesajı olmadan çöktü. Neden en azından derleme zamanı uyarısı vermesin (evrensel uygulamalar için)?
Mike Keskinov

85

Swift 2'de, iPhone ve iPad'de düzgün şekilde göstermek için buna benzer bir şey yapmak istiyorsunuz:

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

Sunucuyu ayarlamazsanız, iPad'de -[UIPopoverPresentationController presentationTransitionWillBegin]aşağıdaki mesajla birlikte bir istisna ile karşılaşırsınız:

Önemli Özel Durum: NSGenericException Uygulamanız, UIAlertControllerStyleActionSheet stilinde bir UIAlertController (<UIAlertController: 0x17858a00>) sundu. Bu stile sahip bir UIAlertController modalPresentationStyle, UIModalPresentationPopover'dır. Uyarı denetleyicisinin popoverPresentationController aracılığıyla bu açılır pencere için konum bilgisi sağlamalısınız. Bir sourceView ve sourceRect veya bir barButtonItem sağlamanız gerekir. Uyarı denetleyicisini sunduğunuzda bu bilgi bilinmiyorsa, UIPopoverPresentationControllerDelegate yönteminde -prepareForPopoverPresentation sağlayabilirsiniz.


28

Swift 3.0 ve üstü için güncelleme

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

Çekmeceyi kullanıyorum, verilen çözümü kullanmaya çalıştım ama başarısız oldum.
Rana Ali Waseem

Kodum yok çünkü işlem sayfasını kaldırıyorum ve uyarı kullanıyorum. Ama benim kodumda sadece bir satır farklıydı let actionSheet = UIAlertController (title: "" ,, message: "", preferStyle: .actionSheet) Ama günlükleri hatırlıyorum, çekmeceden dolayı çöküyordu, çekmecenin açılmaya dirençli olduğunu düşünüyorum eylem sayfası. çünkü ekranın sol köşesinde açılıyordu. sorun sadece iPad'de oldu.
Rana Ali Waseem

15

2018 Güncellemesi

Az önce bu nedenle reddedilen bir uygulama vardı ve çok hızlı bir çözüm, basitçe bir eylem sayfası kullanmaktan bir uyarıya geçmekti.

Büyüleyici oldu ve App Store test kullanıcılarını gayet iyi geçti.

Herkes için uygun bir cevap olmayabilir ama umarım bu, bazılarınızın hızlı bir şekilde turşudan çıkmasına yardımcı olur.


1
Hem iPad hem de iPhone'da mükemmel çalıştı - Teşekkürler
Jeremy Andrews

En iyi çözüm değil. Bazen modern olan actionSheet stilini kullanmak istersiniz.
ShadeToD

15

Swift 5

İPhone için "işlem sayfası" stilini ve iPad için "uyarı" stilini kullandım. iPad, ekranın ortasında görüntülenir. Görünümü herhangi bir yere sabitlemeye veya sourceView belirtmeye gerek yoktur.

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

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

Düzenleme: ShareToD'un önerisine göre, kullanımdan kaldırılan "UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiom.pad" denetimi güncellendi


2
iOS 13'te 'UI_USER_INTERFACE_IDIOM ()', iOS 13.0'da kullanımdan kaldırılmıştır: Doğrudan - [UIDevice userInterfaceIdiom] kullanın. Bunu UIDevice.current.userInterfaceIdiom == .pad
ShadeToD

Bu yaklaşımın bir dezavantajı, sınırlarının dışına tıklandığında uyarının
kapatılmamasıdır

Güzel Çözüm! Teşekkürler!
Pressing_Keys_24_7

11

Swift 4 ve üstü

Bir uzantı oluşturdum

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

Nasıl kullanılır:

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

Deniyorum, ancak xcode 11.2.1'de func addActionSheerForiPad'i arayamıyorum
Rana Ali Waseem

@RanaAliWaseem bunu UIViewController sınıfında mı arıyorsunuz?
ShadeToD

Evet. UIViewController sınıfında diyorum. Ancak UIViewController'dan miras alınan bir Base sınıfı ve Base Class ile miras alınır.
Rana Ali Waseem

8

İşte hızlı bir çözüm:

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
Bu soru UIActivityViewController ile değil, UIAlertController ile ilgili
Roman Truba

Swift 3 için yanıtı UIActivityViewController ile birlikte güncelleyebilir misiniz?
Dia

4

Benim için aşağıdakileri eklemem gerekiyordu:

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

3
İf ifadesini atlayabilir ve isteğe bağlı zincirleme kullanabilirsiniz: alertController.popoverPresentationController? .BarButtonItem = navigationItem.rightBarButtonItem
Dale

2

Eylem sayfanızı sunmadan önce aşağıdaki kodu eklemeniz yeterlidir:

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

0

Swift 4.2 Şu koşulu kullanabilirsiniz:

let alert = UIAlertController(title: nil, message: nil, preferredStyle: UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.