Mempresentasikan UIAlertController dengan benar di iPad menggunakan iOS 8

194

Dengan iOS 8.0, Apple memperkenalkan UIAlertController untuk menggantikan UIActionSheet . Sayangnya, Apple tidak menambahkan informasi tentang cara menyajikannya. Saya menemukan sebuah entri tentang itu di blog hayaGeek, namun, sepertinya tidak berfungsi di iPad. Tampilan benar-benar salah tempat:

Salah tempat: Gambar salah tempat

Benar: masukkan deskripsi gambar di sini

Saya menggunakan kode berikut untuk menunjukkannya di antarmuka:

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

Apakah ada cara lain untuk menambahkannya ke iPad? Atau apakah Apple baru saja melupakan iPad, atau belum diimplementasikan?

Matt3o12
sumber

Jawaban:

284

Anda dapat menyajikan UIAlertControllerdari popover dengan menggunakan UIPopoverPresentationController.

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

Mengedit untuk Swift 4.2, meskipun ada banyak blog yang tersedia untuk hal yang sama tetapi mungkin menghemat waktu Anda untuk pergi dan mencari mereka.

 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
sumber
Gunakan [alertController.view setTintColor: [UIColor blackColor]]; jika Anda tidak melihat teksnya. UIAlertController menggunakan warna warna jendela secara default, yang mungkin putih dan tidak terlihat dalam contoh ini.
whyoz
2
Tombol Batal tidak ditampilkan di iPad
Bhavin Ramani
14
@BhavinRamani tombol Batalkan dihapus dari popover secara otomatis, karena mengetuk di luar popover mewakili "membatalkan", dalam konteks popover.
christopherdrum
ini luar biasa, masalah saya terpecahkan! Terima kasih banyak!
Mahir Tayir
109

Di iPad, peringatan akan ditampilkan sebagai sembulan menggunakan UIPopoverPresentationController yang baru , ia mengharuskan Anda menentukan titik jangkar untuk penyajian sembulan dengan menggunakan sourceView dan sourceRect atau barButtonItem

  • barButtonItem
  • sourceView
  • sourceRect

Untuk menentukan titik jangkar, Anda harus mendapatkan referensi ke UIPopoverPresentationController UIAlertController's dan mengatur salah satu properti sebagai berikut:

alertController.popoverPresentationController.barButtonItem = button;

Kode sampel:

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
sumber
28
Itu bukan "salah satu dari tiga" properti anchor point; itu adalah: "baik sourceView dan sourceRect atau barButtonItem".
Roller
2
+1 untuk Rolleric. Dokumentasi Apple menyatakan tentang sourceRect: "Gunakan properti ini bersama dengan properti sourceView untuk menentukan lokasi anchor untuk popover. Atau, Anda dapat menentukan lokasi anchor untuk popover menggunakan properti barButtonItem." - developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Ben Patch
Oh man. Itu hanya macet tanpa pesan log. Mengapa setidaknya tidak memberikan peringatan waktu kompilasi (untuk aplikasi universal)?
Mike Keskinov
85

Di Swift 2, Anda ingin melakukan sesuatu seperti ini untuk menunjukkannya dengan benar di iPhone dan 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)
}

Jika Anda tidak mengatur presenter, Anda akan berakhir dengan pengecualian pada iPad -[UIPopoverPresentationController presentationTransitionWillBegin]dengan pesan berikut:

Pengecualian Fatal: NSGenericException Aplikasi Anda telah menyajikan UIAlertController (<UIAlertController: 0x17858a00>) dengan gaya UIAlertControllerStyleActionSheet. ModalPresentationStyle dari UIAlertController dengan gaya ini adalah UIModalPresentationPopover. Anda harus memberikan informasi lokasi untuk popover ini melalui popoverPresentationController pengontrol peringatan. Anda harus menyediakan sourceView dan sourceRect atau barButtonItem. Jika informasi ini tidak diketahui saat Anda menampilkan pengontrol lansiran, Anda dapat memberikannya dalam metode UIPopoverPresentationControllerDelegate -prepareForPopoverPresentation.

kviksilver
sumber
26

Pembaruan untuk Swift 3.0 dan lebih tinggi

    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
sumber
Saya menggunakan laci, saya mencoba menggunakan solusi yang diberikan tetapi gagal.
Rana Ali Waseem
Saya tidak punya kode, karena saya menghapus lembar tindakan dan menggunakan lansiran. Tetapi dalam kode saya hanya satu baris yang berbeda, biarkan actionSheet = UIAlertController (judul: "" ,, pesan: "", preferStyle: .actionSheet) Tapi saya ingat log, itu macet karena laci, saya pikir laci itu menolak untuk membuka lembar tindakan. karena sedang membuka di sudut kiri layar. Masalahnya hanya di iPad.
Rana Ali Waseem
15

Pembaruan 2018

Saya baru saja menolak aplikasi karena alasan ini dan resolusi yang sangat cepat adalah hanya mengubah dari menggunakan lembar tindakan ke peringatan.

Bekerja dengan baik dan melewati penguji App Store dengan baik.

Mungkin bukan jawaban yang cocok untuk semua orang tetapi saya harap ini membantu beberapa dari Anda keluar dari acar dengan cepat.

Kotak Lagu
sumber
1
Bekerja dengan sempurna pada iPad & iPhone - Terima kasih
Jeremy Andrews
Itu bukan solusi terbaik. Terkadang Anda ingin menggunakan gaya actionSheet, yang modern.
ShadeToD
9

Cepat 4 dan lebih tinggi

Saya telah membuat ekstensi

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

Cara Penggunaan:

let actionSheetVC = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
addActionSheetForIpad(actionSheet: actionSheetVC)
present(actionSheetVC, animated: true, completion: nil)
Siddhesh Mahadeshwar
sumber
Saya mencobanya tetapi tidak dapat memanggil func addActionSheerForiPad di xcode 11.2.1
Rana Ali Waseem
@RanaAliWaseem apakah Anda memanggil ini di dalam kelas UIViewController?
ShadeToD
Iya. Saya menyebutnya di kelas UIViewController. Tapi ini diwarisi dengan kelas Base dan Kelas Base diwarisi dari UIViewController.
Rana Ali Waseem
8

Inilah solusi cepat:

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
sumber
3
Pertanyaan ini tentang UIAlertController, bukan UIActivityViewController
Roman Truba
Bisakah Anda memperbarui jawaban untuk Swift 3 bersama dengan UIActivityViewController?
Dia
7

Cepat 5

Saya menggunakan gaya "actionsheet" untuk iPhone dan "waspada" untuk iPad. iPad ditampilkan di tengah layar. Tidak perlu menentukan sourceView atau jangkar tampilan di mana saja.

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

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

Sunting: Per saran ShareToD, perbarui usang "UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiom.pad" centang

Greg T
sumber
2
di iOS 13 'UI_USER_INTERFACE_IDIOM ()' sudah tidak digunakan lagi di iOS 13.0: Gunakan - [UIDevice userInterfaceIdiom] secara langsung. Anda harus mengubahnya ke UIDevice.current.userInterfaceIdiom == .pad
ShadeToD
2

Bagi saya, saya hanya perlu menambahkan yang berikut:

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}
Matthew Becker
sumber
2
Anda dapat menghilangkan pernyataan if dan menggunakan perangkaian opsional: alertController.popoverPresentationController? .BarButtonItem = navigationItem.rightBarButtonItem
Dale
2

Cukup tambahkan kode berikut sebelum menyajikan lembar tindakan Anda:

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